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