Home | History | Annotate | Download | only in collect
      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 
     17 package com.google.common.collect;
     18 
     19 import static com.google.common.collect.Lists.newArrayList;
     20 import static com.google.common.testing.SerializableTester.reserialize;
     21 import static com.google.common.testing.SerializableTester.reserializeAndAssert;
     22 import static java.util.Arrays.asList;
     23 import static org.junit.contrib.truth.Truth.ASSERT;
     24 
     25 import com.google.common.annotations.GwtCompatible;
     26 import com.google.common.annotations.GwtIncompatible;
     27 import com.google.common.base.Function;
     28 import com.google.common.base.Functions;
     29 import com.google.common.collect.Ordering.ArbitraryOrdering;
     30 import com.google.common.collect.Ordering.IncomparableValueException;
     31 import com.google.common.collect.testing.Helpers;
     32 import com.google.common.testing.EqualsTester;
     33 import com.google.common.testing.NullPointerTester;
     34 
     35 import junit.framework.TestCase;
     36 
     37 import java.util.Arrays;
     38 import java.util.Collections;
     39 import java.util.Comparator;
     40 import java.util.Iterator;
     41 import java.util.List;
     42 import java.util.Random;
     43 import java.util.RandomAccess;
     44 
     45 import javax.annotation.Nullable;
     46 
     47 /**
     48  * Unit tests for {@code Ordering}.
     49  *
     50  * @author Jesse Wilson
     51  */
     52 @GwtCompatible(emulated = true)
     53 public 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