1/*
2 * Copyright (C) 2007 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
17package com.google.common.collect;
18
19import static com.google.common.collect.Lists.newArrayList;
20import static com.google.common.testing.SerializableTester.reserialize;
21import static com.google.common.testing.SerializableTester.reserializeAndAssert;
22import static java.util.Arrays.asList;
23import static org.junit.contrib.truth.Truth.ASSERT;
24
25import com.google.common.annotations.GwtCompatible;
26import com.google.common.annotations.GwtIncompatible;
27import com.google.common.base.Function;
28import com.google.common.base.Functions;
29import com.google.common.collect.Ordering.ArbitraryOrdering;
30import com.google.common.collect.Ordering.IncomparableValueException;
31import com.google.common.collect.testing.Helpers;
32import com.google.common.testing.EqualsTester;
33import com.google.common.testing.NullPointerTester;
34
35import junit.framework.TestCase;
36
37import java.util.Arrays;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.Iterator;
41import java.util.List;
42import java.util.Random;
43import java.util.RandomAccess;
44
45import javax.annotation.Nullable;
46
47/**
48 * Unit tests for {@code Ordering}.
49 *
50 * @author Jesse Wilson
51 */
52@GwtCompatible(emulated = true)
53public class OrderingTest extends TestCase {
54  // TODO(cpovirk): some of these are inexplicably slow (20-30s) under GWT
55
56  private final Ordering<Number> numberOrdering = new NumberOrdering();
57
58  public void testNatural() {
59    Ordering<Integer> comparator = Ordering.natural();
60    Helpers.testComparator(comparator,
61        Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE);
62    try {
63      comparator.compare(1, null);
64      fail();
65    } catch (NullPointerException expected) {}
66    try {
67      comparator.compare(null, 2);
68      fail();
69    } catch (NullPointerException expected) {}
70    try {
71      comparator.compare(null, null);
72      fail();
73    } catch (NullPointerException expected) {}
74    assertSame(comparator, reserialize(comparator));
75    assertEquals("Ordering.natural()", comparator.toString());
76  }
77
78  public void testFrom() {
79    Ordering<String> caseInsensitiveOrdering
80        = Ordering.from(String.CASE_INSENSITIVE_ORDER);
81    assertEquals(0, caseInsensitiveOrdering.compare("A", "a"));
82    assertTrue(caseInsensitiveOrdering.compare("a", "B") < 0);
83    assertTrue(caseInsensitiveOrdering.compare("B", "a") > 0);
84
85    @SuppressWarnings("deprecation") // test of deprecated method
86    Ordering<String> orderingFromOrdering =
87        Ordering.from(Ordering.<String>natural());
88    new EqualsTester()
89        .addEqualityGroup(caseInsensitiveOrdering, Ordering.from(String.CASE_INSENSITIVE_ORDER))
90        .addEqualityGroup(orderingFromOrdering, Ordering.natural())
91        .testEquals();
92  }
93
94  public void testExplicit_none() {
95    Comparator<Integer> c
96        = Ordering.explicit(Collections.<Integer>emptyList());
97    try {
98      c.compare(0, 0);
99      fail();
100    } catch (IncomparableValueException expected) {
101      assertEquals(0, expected.value);
102    }
103    reserializeAndAssert(c);
104  }
105
106  public void testExplicit_one() {
107    Comparator<Integer> c = Ordering.explicit(0);
108    assertEquals(0, c.compare(0, 0));
109    try {
110      c.compare(0, 1);
111      fail();
112    } catch (IncomparableValueException expected) {
113      assertEquals(1, expected.value);
114    }
115    reserializeAndAssert(c);
116    assertEquals("Ordering.explicit([0])", c.toString());
117  }
118
119  public void testExplicit_two() {
120    Comparator<Integer> c = Ordering.explicit(42, 5);
121    assertEquals(0, c.compare(5, 5));
122    assertTrue(c.compare(5, 42) > 0);
123    assertTrue(c.compare(42, 5) < 0);
124    try {
125      c.compare(5, 666);
126      fail();
127    } catch (IncomparableValueException expected) {
128      assertEquals(666, expected.value);
129    }
130    new EqualsTester()
131        .addEqualityGroup(c, Ordering.explicit(42, 5))
132        .addEqualityGroup(Ordering.explicit(5, 42))
133        .addEqualityGroup(Ordering.explicit(42))
134        .testEquals();
135    reserializeAndAssert(c);
136  }
137
138  public void testExplicit_sortingExample() {
139    Comparator<Integer> c
140        = Ordering.explicit(2, 8, 6, 1, 7, 5, 3, 4, 0, 9);
141    List<Integer> list = Arrays.asList(0, 3, 5, 6, 7, 8, 9);
142    Collections.sort(list, c);
143    ASSERT.that(list).hasContentsInOrder(8, 6, 7, 5, 3, 0, 9);
144    reserializeAndAssert(c);
145  }
146
147  public void testExplicit_withDuplicates() {
148    try {
149      Ordering.explicit(1, 2, 3, 4, 2);
150      fail();
151    } catch (IllegalArgumentException expected) {
152    }
153  }
154
155  // A more limited test than the one that follows, but this one uses the
156  // actual public API.
157  public void testArbitrary_withoutCollisions() {
158    List<Object> list = Lists.newArrayList();
159    for (int i = 0; i < 50; i++) {
160      list.add(new Object());
161    }
162
163    Ordering<Object> arbitrary = Ordering.arbitrary();
164    Collections.sort(list, arbitrary);
165
166    // Now we don't care what order it's put the list in, only that
167    // comparing any pair of elements gives the answer we expect.
168    Helpers.testComparator(arbitrary, list);
169
170    assertEquals("Ordering.arbitrary()", arbitrary.toString());
171  }
172
173  public void testArbitrary_withCollisions() {
174    List<Integer> list = Lists.newArrayList();
175    for (int i = 0; i < 50; i++) {
176      list.add(i);
177    }
178
179    Ordering<Object> arbitrary = new ArbitraryOrdering() {
180      @Override int identityHashCode(Object object) {
181        return ((Integer) object) % 5; // fake tons of collisions!
182      }
183    };
184
185    // Don't let the elements be in such a predictable order
186    list = shuffledCopy(list, new Random(1));
187
188    Collections.sort(list, arbitrary);
189
190    // Now we don't care what order it's put the list in, only that
191    // comparing any pair of elements gives the answer we expect.
192    Helpers.testComparator(arbitrary, list);
193  }
194
195  public void testUsingToString() {
196    Ordering<Object> ordering = Ordering.usingToString();
197    Helpers.testComparator(ordering, 1, 12, 124, 2);
198    assertEquals("Ordering.usingToString()", ordering.toString());
199    assertSame(ordering, reserialize(ordering));
200  }
201
202  // use an enum to get easy serializability
203  private enum CharAtFunction implements Function<String, Character> {
204    AT0(0),
205    AT1(1),
206    AT2(2),
207    AT3(3),
208    AT4(4),
209    AT5(5),
210    ;
211
212    final int index;
213    CharAtFunction(int index) {
214      this.index = index;
215    }
216    @Override
217    public Character apply(String string) {
218      return string.charAt(index);
219    }
220  }
221
222  private static Ordering<String> byCharAt(int index) {
223    return Ordering.natural().onResultOf(CharAtFunction.values()[index]);
224  }
225
226  public void testCompound_static() {
227    Comparator<String> comparator = Ordering.compound(asList(
228        byCharAt(0), byCharAt(1), byCharAt(2),
229        byCharAt(3), byCharAt(4), byCharAt(5)));
230    Helpers.testComparator(comparator, ImmutableList.of(
231        "applesauce",
232        "apricot",
233        "artichoke",
234        "banality",
235        "banana",
236        "banquet",
237        "tangelo",
238        "tangerine"));
239    reserializeAndAssert(comparator);
240  }
241
242  public void testCompound_instance() {
243    Comparator<String> comparator = byCharAt(1).compound(byCharAt(0));
244    Helpers.testComparator(comparator, ImmutableList.of(
245        "red",
246        "yellow",
247        "violet",
248        "blue",
249        "indigo",
250        "green",
251        "orange"));
252  }
253
254  public void testCompound_instance_generics() {
255    Ordering<Object> objects = Ordering.explicit((Object) 1);
256    Ordering<Number> numbers = Ordering.explicit((Number) 1);
257    Ordering<Integer> integers = Ordering.explicit(1);
258
259    // Like by like equals like
260    Ordering<Number> a = numbers.compound(numbers);
261
262    // The compound takes the more specific type of the two, regardless of order
263
264    Ordering<Number> b = numbers.compound(objects);
265    Ordering<Number> c = objects.compound(numbers);
266
267    Ordering<Integer> d = numbers.compound(integers);
268    Ordering<Integer> e = integers.compound(numbers);
269
270    // This works with three levels too (IDEA falsely reports errors as noted
271    // below. Both javac and eclipse handle these cases correctly.)
272
273    Ordering<Number> f = numbers.compound(objects).compound(objects); //bad IDEA
274    Ordering<Number> g = objects.compound(numbers).compound(objects);
275    Ordering<Number> h = objects.compound(objects).compound(numbers);
276
277    Ordering<Number> i = numbers.compound(objects.compound(objects));
278    Ordering<Number> j = objects.compound(numbers.compound(objects)); //bad IDEA
279    Ordering<Number> k = objects.compound(objects.compound(numbers));
280
281    // You can also arbitrarily assign a more restricted type - not an intended
282    // feature, exactly, but unavoidable (I think) and harmless
283    Ordering<Integer> l = objects.compound(numbers);
284
285    // This correctly doesn't work:
286    // Ordering<Object> m = numbers.compound(objects);
287
288    // Sadly, the following works in javac 1.6, but at least it fails for
289    // eclipse, and is *correctly* highlighted red in IDEA.
290    // Ordering<Object> n = objects.compound(numbers);
291  }
292
293  public void testReverse() {
294    Ordering<Number> reverseOrder = numberOrdering.reverse();
295    Helpers.testComparator(reverseOrder,
296        Integer.MAX_VALUE, 1, 0, -1, Integer.MIN_VALUE);
297
298    new EqualsTester()
299        .addEqualityGroup(reverseOrder, numberOrdering.reverse())
300        .addEqualityGroup(Ordering.natural().reverse())
301        .addEqualityGroup(Collections.reverseOrder())
302        .testEquals();
303  }
304
305  public void testReverseOfReverseSameAsForward() {
306    // Not guaranteed by spec, but it works, and saves us from testing
307    // exhaustively
308    assertSame(numberOrdering, numberOrdering.reverse().reverse());
309  }
310
311  private enum StringLengthFunction implements Function<String, Integer> {
312    StringLength;
313
314    @Override
315    public Integer apply(String string) {
316      return string.length();
317    }
318  }
319
320  private static final Ordering<Integer> DECREASING_INTEGER
321      = Ordering.natural().reverse();
322
323  public void testOnResultOf_natural() {
324    Comparator<String> comparator
325        = Ordering.natural().onResultOf(StringLengthFunction.StringLength);
326    assertTrue(comparator.compare("to", "be") == 0);
327    assertTrue(comparator.compare("or", "not") < 0);
328    assertTrue(comparator.compare("that", "to") > 0);
329
330    new EqualsTester()
331        .addEqualityGroup(
332            comparator,
333            Ordering.natural().onResultOf(StringLengthFunction.StringLength))
334        .addEqualityGroup(DECREASING_INTEGER)
335        .testEquals();
336    reserializeAndAssert(comparator);
337    assertEquals("Ordering.natural().onResultOf(StringLength)",
338        comparator.toString());
339  }
340
341  public void testOnResultOf_chained() {
342    Comparator<String> comparator = DECREASING_INTEGER.onResultOf(
343        StringLengthFunction.StringLength);
344    assertTrue(comparator.compare("to", "be") == 0);
345    assertTrue(comparator.compare("not", "or") < 0);
346    assertTrue(comparator.compare("to", "that") > 0);
347
348    new EqualsTester()
349        .addEqualityGroup(
350            comparator,
351            DECREASING_INTEGER.onResultOf(StringLengthFunction.StringLength))
352        .addEqualityGroup(
353            DECREASING_INTEGER.onResultOf(Functions.constant(1)))
354        .addEqualityGroup(Ordering.natural())
355        .testEquals();
356    reserializeAndAssert(comparator);
357    assertEquals("Ordering.natural().reverse().onResultOf(StringLength)",
358        comparator.toString());
359  }
360
361  @SuppressWarnings("unchecked") // dang varargs
362  public void testLexicographical() {
363    Ordering<String> ordering = Ordering.natural();
364    Ordering<Iterable<String>> lexy = ordering.lexicographical();
365
366    ImmutableList<String> empty = ImmutableList.of();
367    ImmutableList<String> a = ImmutableList.of("a");
368    ImmutableList<String> aa = ImmutableList.of("a", "a");
369    ImmutableList<String> ab = ImmutableList.of("a", "b");
370    ImmutableList<String> b = ImmutableList.of("b");
371
372    Helpers.testComparator(lexy, empty, a, aa, ab, b);
373  }
374
375  public void testNullsFirst() {
376    Ordering<Integer> ordering = Ordering.natural().nullsFirst();
377    Helpers.testComparator(ordering, null, Integer.MIN_VALUE, 0, 1);
378  }
379
380  public void testNullsLast() {
381    Ordering<Integer> ordering = Ordering.natural().nullsLast();
382    Helpers.testComparator(ordering, 0, 1, Integer.MAX_VALUE, null);
383  }
384
385  public void testBinarySearch() {
386    List<Integer> ints = Lists.newArrayList(0, 2, 3, 5, 7, 9);
387    assertEquals(4, numberOrdering.binarySearch(ints, 7));
388  }
389
390  public void testSortedCopy() {
391    List<Integer> unsortedInts = Collections.unmodifiableList(
392        Arrays.asList(5, 0, 3, null, 0, 9));
393    List<Integer> sortedInts =
394        numberOrdering.nullsLast().sortedCopy(unsortedInts);
395    assertEquals(Arrays.asList(0, 0, 3, 5, 9, null), sortedInts);
396
397    assertEquals(Collections.emptyList(),
398        numberOrdering.sortedCopy(Collections.<Integer>emptyList()));
399  }
400
401  public void testImmutableSortedCopy() {
402    ImmutableList<Integer> unsortedInts = ImmutableList.of(5, 3, 0, 9, 3);
403    ImmutableList<Integer> sortedInts
404        = numberOrdering.immutableSortedCopy(unsortedInts);
405    assertEquals(Arrays.asList(0, 3, 3, 5, 9), sortedInts);
406
407    assertEquals(Collections.<Integer>emptyList(),
408        numberOrdering.immutableSortedCopy(Collections.<Integer>emptyList()));
409
410    List<Integer> listWithNull = Arrays.asList(5, 3, null, 9);
411    try {
412      Ordering.natural().nullsFirst().immutableSortedCopy(listWithNull);
413      fail();
414    } catch (NullPointerException expected) {
415    }
416  }
417
418  public void testIsOrdered() {
419    assertFalse(numberOrdering.isOrdered(asList(5, 3, 0, 9)));
420    assertFalse(numberOrdering.isOrdered(asList(0, 5, 3, 9)));
421    assertTrue(numberOrdering.isOrdered(asList(0, 3, 5, 9)));
422    assertTrue(numberOrdering.isOrdered(asList(0, 0, 3, 3)));
423    assertTrue(numberOrdering.isOrdered(asList(0, 3)));
424    assertTrue(numberOrdering.isOrdered(Collections.singleton(1)));
425    assertTrue(numberOrdering.isOrdered(Collections.<Integer>emptyList()));
426  }
427
428  public void testIsStrictlyOrdered() {
429    assertFalse(numberOrdering.isStrictlyOrdered(asList(5, 3, 0, 9)));
430    assertFalse(numberOrdering.isStrictlyOrdered(asList(0, 5, 3, 9)));
431    assertTrue(numberOrdering.isStrictlyOrdered(asList(0, 3, 5, 9)));
432    assertFalse(numberOrdering.isStrictlyOrdered(asList(0, 0, 3, 3)));
433    assertTrue(numberOrdering.isStrictlyOrdered(asList(0, 3)));
434    assertTrue(numberOrdering.isStrictlyOrdered(Collections.singleton(1)));
435    assertTrue(numberOrdering.isStrictlyOrdered(
436        Collections.<Integer>emptyList()));
437  }
438
439  public void testLeastOf_emptyList_0() {
440    List<Integer> result = numberOrdering.leastOf(Arrays.<Integer>asList(), 0);
441    assertTrue(result instanceof RandomAccess);
442    assertListImmutable(result);
443    assertEquals(ImmutableList.<Integer>of(), result);
444  }
445
446  public void testLeastOf_emptyList_1() {
447    List<Integer> result = numberOrdering.leastOf(Arrays.<Integer>asList(), 1);
448    assertTrue(result instanceof RandomAccess);
449    assertListImmutable(result);
450    assertEquals(ImmutableList.<Integer>of(), result);
451  }
452
453  public void testLeastOf_simple_negativeOne() {
454    try {
455      numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), -1);
456      fail();
457    } catch (IllegalArgumentException expected) {
458    }
459  }
460
461  public void testLeastOf_singletonList_0() {
462    List<Integer> result = numberOrdering.leastOf(Arrays.asList(3), 0);
463    assertTrue(result instanceof RandomAccess);
464    assertListImmutable(result);
465    assertEquals(ImmutableList.<Integer>of(), result);
466  }
467
468  public void testLeastOf_simple_0() {
469    List<Integer> result = numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), 0);
470    assertTrue(result instanceof RandomAccess);
471    assertListImmutable(result);
472    assertEquals(ImmutableList.<Integer>of(), result);
473  }
474
475  public void testLeastOf_simple_1() {
476    List<Integer> result = numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), 1);
477    assertTrue(result instanceof RandomAccess);
478    assertListImmutable(result);
479    assertEquals(ImmutableList.of(-1), result);
480  }
481
482  public void testLeastOf_simple_nMinusOne() {
483    List<Integer> list = Arrays.asList(3, 4, 5, -1);
484    List<Integer> result = numberOrdering.leastOf(list, list.size() - 1);
485    assertTrue(result instanceof RandomAccess);
486    assertListImmutable(result);
487    assertEquals(ImmutableList.of(-1, 3, 4), result);
488  }
489
490  public void testLeastOf_simple_n() {
491    List<Integer> list = Arrays.asList(3, 4, 5, -1);
492    List<Integer> result = numberOrdering.leastOf(list, list.size());
493    assertTrue(result instanceof RandomAccess);
494    assertListImmutable(result);
495    assertEquals(ImmutableList.of(-1, 3, 4, 5), result);
496  }
497
498  public void testLeastOf_simple_nPlusOne() {
499    List<Integer> list = Arrays.asList(3, 4, 5, -1);
500    List<Integer> result = numberOrdering.leastOf(list, list.size() + 1);
501    assertTrue(result instanceof RandomAccess);
502    assertListImmutable(result);
503    assertEquals(ImmutableList.of(-1, 3, 4, 5), result);
504  }
505
506  public void testLeastOf_ties() {
507    Integer foo = new Integer(Integer.MAX_VALUE - 10);
508    Integer bar = new Integer(Integer.MAX_VALUE - 10);
509
510    assertNotSame(foo, bar);
511    assertEquals(foo, bar);
512
513    List<Integer> list = Arrays.asList(3, foo, bar, -1);
514    List<Integer> result = numberOrdering.leastOf(list, list.size());
515    assertEquals(ImmutableList.of(-1, 3, foo, bar), result);
516  }
517
518  @GwtIncompatible("slow")
519  public void testLeastOf_reconcileAgainstSortAndSublist() {
520    runLeastOfComparison(1000, 300, 20);
521  }
522
523  public void testLeastOf_reconcileAgainstSortAndSublistSmall() {
524    runLeastOfComparison(10, 30, 2);
525  }
526
527  private static void runLeastOfComparison(
528      int iterations, int elements, int seeds) {
529    Random random = new Random(42);
530    Ordering<Integer> ordering = Ordering.natural();
531
532    for (int i = 0; i < iterations; i++) {
533      List<Integer> list = Lists.newArrayList();
534      for (int j = 0; j < elements; j++) {
535        list.add(random.nextInt(10 * i + j + 1));
536      }
537
538      for (int seed = 1; seed < seeds; seed++) {
539        int k = random.nextInt(10 * seed);
540        assertEquals(ordering.sortedCopy(list).subList(0, k),
541            ordering.leastOf(list, k));
542      }
543    }
544  }
545
546  public void testGreatestOf_simple() {
547    /*
548     * If greatestOf() promised to be implemented as reverse().leastOf(), this
549     * test would be enough. It doesn't... but we'll cheat and act like it does
550     * anyway. There's a comment there to remind us to fix this if we change it.
551     */
552    List<Integer> list = Arrays.asList(3, 1, 3, 2, 4, 2, 4, 3);
553    assertEquals(Arrays.asList(4, 4, 3, 3), numberOrdering.greatestOf(list, 4));
554  }
555
556  private static void assertListImmutable(List<Integer> result) {
557    try {
558      result.set(0, 1);
559      fail();
560    } catch (UnsupportedOperationException expected) {
561      // pass
562    }
563  }
564
565  public void testIteratorMinAndMax() {
566    List<Integer> ints = Lists.newArrayList(5, 3, 0, 9);
567    assertEquals(9, (int) numberOrdering.max(ints.iterator()));
568    assertEquals(0, (int) numberOrdering.min(ints.iterator()));
569
570    // when the values are the same, the first argument should be returned
571    Integer a = new Integer(4);
572    Integer b = new Integer(4);
573    ints = Lists.newArrayList(a, b, b);
574    assertSame(a, numberOrdering.max(ints.iterator()));
575    assertSame(a, numberOrdering.min(ints.iterator()));
576  }
577
578  public void testIteratorMinExhaustsIterator() {
579    List<Integer> ints = Lists.newArrayList(9, 0, 3, 5);
580    Iterator<Integer> iterator = ints.iterator();
581    assertEquals(0, (int) numberOrdering.min(iterator));
582    assertFalse(iterator.hasNext());
583  }
584
585  public void testIteratorMaxExhaustsIterator() {
586    List<Integer> ints = Lists.newArrayList(9, 0, 3, 5);
587    Iterator<Integer> iterator = ints.iterator();
588    assertEquals(9, (int) numberOrdering.max(iterator));
589    assertFalse(iterator.hasNext());
590  }
591
592  public void testIterableMinAndMax() {
593    List<Integer> ints = Lists.newArrayList(5, 3, 0, 9);
594    assertEquals(9, (int) numberOrdering.max(ints));
595    assertEquals(0, (int) numberOrdering.min(ints));
596
597    // when the values are the same, the first argument should be returned
598    Integer a = new Integer(4);
599    Integer b = new Integer(4);
600    ints = Lists.newArrayList(a, b, b);
601    assertSame(a, numberOrdering.max(ints));
602    assertSame(a, numberOrdering.min(ints));
603  }
604
605  public void testVarargsMinAndMax() {
606    // try the min and max values in all positions, since some values are proper
607    // parameters and others are from the varargs array
608    assertEquals(9, (int) numberOrdering.max(9, 3, 0, 5, 8));
609    assertEquals(9, (int) numberOrdering.max(5, 9, 0, 3, 8));
610    assertEquals(9, (int) numberOrdering.max(5, 3, 9, 0, 8));
611    assertEquals(9, (int) numberOrdering.max(5, 3, 0, 9, 8));
612    assertEquals(9, (int) numberOrdering.max(5, 3, 0, 8, 9));
613    assertEquals(0, (int) numberOrdering.min(0, 3, 5, 9, 8));
614    assertEquals(0, (int) numberOrdering.min(5, 0, 3, 9, 8));
615    assertEquals(0, (int) numberOrdering.min(5, 3, 0, 9, 8));
616    assertEquals(0, (int) numberOrdering.min(5, 3, 9, 0, 8));
617    assertEquals(0, (int) numberOrdering.min(5, 3, 0, 9, 0));
618
619    // when the values are the same, the first argument should be returned
620    Integer a = new Integer(4);
621    Integer b = new Integer(4);
622    assertSame(a, numberOrdering.max(a, b, b));
623    assertSame(a, numberOrdering.min(a, b, b));
624  }
625
626  public void testParameterMinAndMax() {
627    assertEquals(5, (int) numberOrdering.max(3, 5));
628    assertEquals(5, (int) numberOrdering.max(5, 3));
629    assertEquals(3, (int) numberOrdering.min(3, 5));
630    assertEquals(3, (int) numberOrdering.min(5, 3));
631
632    // when the values are the same, the first argument should be returned
633    Integer a = new Integer(4);
634    Integer b = new Integer(4);
635    assertSame(a, numberOrdering.max(a, b));
636    assertSame(a, numberOrdering.min(a, b));
637  }
638
639  private static class NumberOrdering extends Ordering<Number> {
640    @Override public int compare(Number a, Number b) {
641      return ((Double) a.doubleValue()).compareTo(b.doubleValue());
642    }
643    @Override public int hashCode() {
644      return NumberOrdering.class.hashCode();
645    }
646    @Override public boolean equals(Object other) {
647      return other instanceof NumberOrdering;
648    }
649    private static final long serialVersionUID = 0;
650  }
651
652  /*
653   * Now we have monster tests that create hundreds of Orderings using different
654   * combinations of methods, then checks compare(), binarySearch() and so
655   * forth on each one.
656   */
657
658  // should periodically try increasing this, but it makes the test run long
659  private static final int RECURSE_DEPTH = 2;
660
661  public void testCombinationsExhaustively_startingFromNatural() {
662    testExhaustively(Ordering.<String>natural(), Arrays.asList("a", "b"));
663  }
664
665  public void testCombinationsExhaustively_startingFromExplicit() {
666    testExhaustively(Ordering.explicit("a", "b", "c", "d"),
667        Arrays.asList("b", "d"));
668  }
669
670  public void testCombinationsExhaustively_startingFromUsingToString() {
671    testExhaustively(Ordering.usingToString(), Arrays.asList(1, 12, 2));
672  }
673
674  public void testCombinationsExhaustively_startingFromArbitrary() {
675    Ordering<Object> arbitrary = Ordering.arbitrary();
676    List<Object> list = Arrays.asList(1, "foo", new Object());
677
678    // There's no way to tell what the order should be except empirically
679    Collections.sort(list, arbitrary);
680    testExhaustively(arbitrary, list);
681  }
682
683  private static <T> void testExhaustively(
684      Ordering<? super T> ordering, List<T> list) {
685    // shoot me, but I didn't want to deal with wildcards through the whole test
686    @SuppressWarnings("unchecked")
687    Scenario<T> starter = new Scenario<T>((Ordering) ordering, list);
688    verifyScenario(starter, 0);
689  }
690
691  private static <T> void verifyScenario(Scenario<T> scenario, int level) {
692    scenario.testCompareTo();
693    scenario.testIsOrdered();
694    scenario.testMinAndMax();
695    scenario.testBinarySearch();
696
697    if (level < RECURSE_DEPTH) {
698      for (OrderingMutation alteration : OrderingMutation.values()) {
699        verifyScenario(alteration.mutate(scenario), level + 1);
700      }
701    }
702  }
703
704  /**
705   * An aggregation of an ordering with a list (of size > 1) that should prove
706   * to be in strictly increasing order according to that ordering.
707   */
708  private static class Scenario<T> {
709    final Ordering<T> ordering;
710    final List<T> strictlyOrderedList;
711
712    Scenario(Ordering<T> ordering, List<T> strictlyOrderedList) {
713      this.ordering = ordering;
714      this.strictlyOrderedList = strictlyOrderedList;
715    }
716
717    void testCompareTo() {
718      Helpers.testComparator(ordering, strictlyOrderedList);
719    }
720
721    void testIsOrdered() {
722      assertTrue(ordering.isOrdered(strictlyOrderedList));
723      assertTrue(ordering.isStrictlyOrdered(strictlyOrderedList));
724    }
725
726    void testMinAndMax() {
727      List<T> shuffledList = Lists.newArrayList(strictlyOrderedList);
728      shuffledList = shuffledCopy(shuffledList, new Random(5));
729
730      assertEquals(strictlyOrderedList.get(0), ordering.min(shuffledList));
731      assertEquals(strictlyOrderedList.get(strictlyOrderedList.size() - 1),
732          ordering.max(shuffledList));
733    }
734
735    void testBinarySearch() {
736      for (int i = 0; i < strictlyOrderedList.size(); i++) {
737        assertEquals(i, ordering.binarySearch(
738            strictlyOrderedList, strictlyOrderedList.get(i)));
739      }
740      List<T> newList = Lists.newArrayList(strictlyOrderedList);
741      T valueNotInList = newList.remove(1);
742      assertEquals(-2, ordering.binarySearch(newList, valueNotInList));
743    }
744  }
745
746  /**
747   * A means for changing an Ordering into another Ordering. Each instance is
748   * responsible for creating the alternate Ordering, and providing a List that
749   * is known to be ordered, based on an input List known to be ordered
750   * according to the input Ordering.
751   */
752  private enum OrderingMutation {
753    REVERSE {
754      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
755        List<T> newList = Lists.newArrayList(scenario.strictlyOrderedList);
756        Collections.reverse(newList);
757        return new Scenario<T>(scenario.ordering.reverse(), newList);
758      }
759    },
760    NULLS_FIRST {
761      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
762        @SuppressWarnings("unchecked")
763        List<T> newList = Lists.newArrayList((T) null);
764        for (T t : scenario.strictlyOrderedList) {
765          if (t != null) {
766            newList.add(t);
767          }
768        }
769        return new Scenario<T>(scenario.ordering.nullsFirst(), newList);
770      }
771    },
772    NULLS_LAST {
773      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
774        List<T> newList = Lists.newArrayList();
775        for (T t : scenario.strictlyOrderedList) {
776          if (t != null) {
777            newList.add(t);
778          }
779        }
780        newList.add(null);
781        return new Scenario<T>(scenario.ordering.nullsLast(), newList);
782      }
783    },
784    ON_RESULT_OF {
785      @Override <T> Scenario<?> mutate(final Scenario<T> scenario) {
786        Ordering<Integer> ordering = scenario.ordering.onResultOf(
787            new Function<Integer, T>() {
788              @Override
789              public T apply(@Nullable Integer from) {
790                return scenario.strictlyOrderedList.get(from);
791              }
792            });
793        List<Integer> list = Lists.newArrayList();
794        for (int i = 0; i < scenario.strictlyOrderedList.size(); i++) {
795          list.add(i);
796        }
797        return new Scenario<Integer>(ordering, list);
798      }
799    },
800    COMPOUND_THIS_WITH_NATURAL {
801      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
802        List<Composite<T>> composites = Lists.newArrayList();
803        for (T t : scenario.strictlyOrderedList) {
804          composites.add(new Composite<T>(t, 1));
805          composites.add(new Composite<T>(t, 2));
806        }
807        Ordering<Composite<T>> ordering =
808            scenario.ordering.onResultOf(Composite.<T>getValueFunction())
809                .compound(Ordering.natural());
810        return new Scenario<Composite<T>>(ordering, composites);
811      }
812    },
813    COMPOUND_NATURAL_WITH_THIS {
814      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
815        List<Composite<T>> composites = Lists.newArrayList();
816        for (T t : scenario.strictlyOrderedList) {
817          composites.add(new Composite<T>(t, 1));
818        }
819        for (T t : scenario.strictlyOrderedList) {
820          composites.add(new Composite<T>(t, 2));
821        }
822        Ordering<Composite<T>> ordering = Ordering.natural().compound(
823            scenario.ordering.onResultOf(Composite.<T>getValueFunction()));
824        return new Scenario<Composite<T>>(ordering, composites);
825      }
826    },
827    LEXICOGRAPHICAL {
828      @SuppressWarnings("unchecked") // dang varargs
829      @Override <T> Scenario<?> mutate(Scenario<T> scenario) {
830        List<Iterable<T>> words = Lists.newArrayList();
831        words.add(Collections.<T>emptyList());
832        for (T t : scenario.strictlyOrderedList) {
833          words.add(Arrays.asList(t));
834          for (T s : scenario.strictlyOrderedList) {
835            words.add(Arrays.asList(t, s));
836          }
837        }
838        return new Scenario<Iterable<T>>(
839            scenario.ordering.lexicographical(), words);
840      }
841    },
842    ;
843
844    abstract <T> Scenario<?> mutate(Scenario<T> scenario);
845  }
846
847  /**
848   * A dummy object we create so that we can have something meaningful to have
849   * a compound ordering over.
850   */
851  private static class Composite<T> implements Comparable<Composite<T>> {
852    final T value;
853    final int rank;
854
855    Composite(T value, int rank) {
856      this.value = value;
857      this.rank = rank;
858    }
859
860    // natural order is by rank only; the test will compound() this with the
861    // order of 't'.
862    @Override
863    public int compareTo(Composite<T> that) {
864      return rank < that.rank ? -1 : rank > that.rank ? 1 : 0;
865    }
866
867    static <T> Function<Composite<T>, T> getValueFunction() {
868      return new Function<Composite<T>, T>() {
869        @Override
870        public T apply(Composite<T> from) {
871          return from.value;
872        }
873      };
874    }
875  }
876
877  @GwtIncompatible("NullPointerTester")
878  public void testNullPointerExceptions() throws Exception {
879    NullPointerTester tester = new NullPointerTester();
880    tester.testAllPublicStaticMethods(Ordering.class);
881
882    // any Ordering<Object> instance that accepts nulls should be good enough
883    tester.testAllPublicInstanceMethods(Ordering.usingToString().nullsFirst());
884  }
885
886  private static <T> List<T> shuffledCopy(List<T> in, Random random) {
887    List<T> mutable = newArrayList(in);
888    List<T> out = newArrayList();
889    while (!mutable.isEmpty()) {
890      out.add(mutable.remove(random.nextInt(mutable.size())));
891    }
892    return out;
893  }
894}
895