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.base.Preconditions.checkArgument; 20 import static com.google.common.collect.Lists.newArrayList; 21 import static com.google.common.testing.SerializableTester.reserialize; 22 import static com.google.common.testing.SerializableTester.reserializeAndAssert; 23 import static com.google.common.truth.Truth.assertThat; 24 import static java.util.Arrays.asList; 25 26 import com.google.common.annotations.GwtCompatible; 27 import com.google.common.annotations.GwtIncompatible; 28 import com.google.common.base.Function; 29 import com.google.common.base.Functions; 30 import com.google.common.collect.Ordering.ArbitraryOrdering; 31 import com.google.common.collect.Ordering.IncomparableValueException; 32 import com.google.common.collect.testing.Helpers; 33 import com.google.common.primitives.Ints; 34 import com.google.common.testing.EqualsTester; 35 import com.google.common.testing.NullPointerTester; 36 import java.util.Arrays; 37 import java.util.Collections; 38 import java.util.Comparator; 39 import java.util.Iterator; 40 import java.util.List; 41 import java.util.Random; 42 import java.util.RandomAccess; 43 import junit.framework.TestCase; 44 import org.checkerframework.checker.nullness.qual.Nullable; 45 46 /** 47 * Unit tests for {@code Ordering}. 48 * 49 * @author Jesse Wilson 50 */ 51 @GwtCompatible(emulated = true) 52 public class OrderingTest extends TestCase { 53 // TODO(cpovirk): some of these are inexplicably slow (20-30s) under GWT 54 55 private final Ordering<Number> numberOrdering = new NumberOrdering(); 56 testAllEqual()57 public void testAllEqual() { 58 Ordering<Object> comparator = Ordering.allEqual(); 59 assertSame(comparator, comparator.reverse()); 60 61 assertEquals(0, comparator.compare(null, null)); 62 assertEquals(0, comparator.compare(new Object(), new Object())); 63 assertEquals(0, comparator.compare("apples", "oranges")); 64 assertSame(comparator, reserialize(comparator)); 65 assertEquals("Ordering.allEqual()", comparator.toString()); 66 67 List<String> strings = ImmutableList.of("b", "a", "d", "c"); 68 assertEquals(strings, comparator.sortedCopy(strings)); 69 assertEquals(strings, comparator.immutableSortedCopy(strings)); 70 } 71 72 // From https://github.com/google/guava/issues/1342 testComplicatedOrderingExample()73 public void testComplicatedOrderingExample() { 74 Integer nullInt = (Integer) null; 75 Ordering<Iterable<Integer>> example = 76 Ordering.<Integer>natural().nullsFirst().reverse().lexicographical().reverse().nullsLast(); 77 List<Integer> list1 = Lists.newArrayList(); 78 List<Integer> list2 = Lists.newArrayList(1); 79 List<Integer> list3 = Lists.newArrayList(1, 1); 80 List<Integer> list4 = Lists.newArrayList(1, 2); 81 List<Integer> list5 = Lists.newArrayList(1, null, 2); 82 List<Integer> list6 = Lists.newArrayList(2); 83 List<Integer> list7 = Lists.newArrayList(nullInt); 84 List<Integer> list8 = Lists.newArrayList(nullInt, nullInt); 85 List<List<Integer>> list = 86 Lists.newArrayList(list1, list2, list3, list4, list5, list6, list7, list8, null); 87 List<List<Integer>> sorted = example.sortedCopy(list); 88 89 // [[null, null], [null], [1, null, 2], [1, 1], [1, 2], [1], [2], [], null] 90 assertThat(sorted) 91 .containsExactly( 92 Lists.newArrayList(nullInt, nullInt), 93 Lists.newArrayList(nullInt), 94 Lists.newArrayList(1, null, 2), 95 Lists.newArrayList(1, 1), 96 Lists.newArrayList(1, 2), 97 Lists.newArrayList(1), 98 Lists.newArrayList(2), 99 Lists.newArrayList(), 100 null) 101 .inOrder(); 102 } 103 testNatural()104 public void testNatural() { 105 Ordering<Integer> comparator = Ordering.natural(); 106 Helpers.testComparator(comparator, Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE); 107 try { 108 comparator.compare(1, null); 109 fail(); 110 } catch (NullPointerException expected) { 111 } 112 try { 113 comparator.compare(null, 2); 114 fail(); 115 } catch (NullPointerException expected) { 116 } 117 try { 118 comparator.compare(null, null); 119 fail(); 120 } catch (NullPointerException expected) { 121 } 122 assertSame(comparator, reserialize(comparator)); 123 assertEquals("Ordering.natural()", comparator.toString()); 124 } 125 testFrom()126 public void testFrom() { 127 Ordering<String> caseInsensitiveOrdering = Ordering.from(String.CASE_INSENSITIVE_ORDER); 128 assertEquals(0, caseInsensitiveOrdering.compare("A", "a")); 129 assertTrue(caseInsensitiveOrdering.compare("a", "B") < 0); 130 assertTrue(caseInsensitiveOrdering.compare("B", "a") > 0); 131 132 @SuppressWarnings("deprecation") // test of deprecated method 133 Ordering<String> orderingFromOrdering = Ordering.from(Ordering.<String>natural()); 134 new EqualsTester() 135 .addEqualityGroup(caseInsensitiveOrdering, Ordering.from(String.CASE_INSENSITIVE_ORDER)) 136 .addEqualityGroup(orderingFromOrdering, Ordering.natural()) 137 .testEquals(); 138 } 139 testExplicit_none()140 public void testExplicit_none() { 141 Comparator<Integer> c = Ordering.explicit(Collections.<Integer>emptyList()); 142 try { 143 c.compare(0, 0); 144 fail(); 145 } catch (IncomparableValueException expected) { 146 assertEquals(0, expected.value); 147 } 148 reserializeAndAssert(c); 149 } 150 testExplicit_one()151 public void testExplicit_one() { 152 Comparator<Integer> c = Ordering.explicit(0); 153 assertEquals(0, c.compare(0, 0)); 154 try { 155 c.compare(0, 1); 156 fail(); 157 } catch (IncomparableValueException expected) { 158 assertEquals(1, expected.value); 159 } 160 reserializeAndAssert(c); 161 assertEquals("Ordering.explicit([0])", c.toString()); 162 } 163 testExplicitMax_b297601553()164 public void testExplicitMax_b297601553() { 165 Ordering<Integer> c = Ordering.explicit(1, 2, 3); 166 167 // TODO(b/297601553): this should probably throw an CCE since 0 isn't explicitly listed 168 assertEquals(0, (int) c.max(asList(0))); 169 try { 170 c.max(asList(0, 1)); 171 fail(); 172 } catch (IncomparableValueException expected) { 173 assertEquals(0, expected.value); 174 } 175 } 176 testExplicit_two()177 public void testExplicit_two() { 178 Comparator<Integer> c = Ordering.explicit(42, 5); 179 assertEquals(0, c.compare(5, 5)); 180 assertTrue(c.compare(5, 42) > 0); 181 assertTrue(c.compare(42, 5) < 0); 182 try { 183 c.compare(5, 666); 184 fail(); 185 } catch (IncomparableValueException expected) { 186 assertEquals(666, expected.value); 187 } 188 new EqualsTester() 189 .addEqualityGroup(c, Ordering.explicit(42, 5)) 190 .addEqualityGroup(Ordering.explicit(5, 42)) 191 .addEqualityGroup(Ordering.explicit(42)) 192 .testEquals(); 193 reserializeAndAssert(c); 194 } 195 196 public void testExplicit_sortingExample() { 197 Comparator<Integer> c = Ordering.explicit(2, 8, 6, 1, 7, 5, 3, 4, 0, 9); 198 List<Integer> list = Arrays.asList(0, 3, 5, 6, 7, 8, 9); 199 Collections.sort(list, c); 200 assertThat(list).containsExactly(8, 6, 7, 5, 3, 0, 9).inOrder(); 201 reserializeAndAssert(c); 202 } 203 204 public void testExplicit_withDuplicates() { 205 try { 206 Ordering.explicit(1, 2, 3, 4, 2); 207 fail(); 208 } catch (IllegalArgumentException expected) { 209 } 210 } 211 212 // A more limited test than the one that follows, but this one uses the 213 // actual public API. 214 public void testArbitrary_withoutCollisions() { 215 List<Object> list = Lists.newArrayList(); 216 for (int i = 0; i < 50; i++) { 217 list.add(new Object()); 218 } 219 220 Ordering<Object> arbitrary = Ordering.arbitrary(); 221 Collections.sort(list, arbitrary); 222 223 // Now we don't care what order it's put the list in, only that 224 // comparing any pair of elements gives the answer we expect. 225 Helpers.testComparator(arbitrary, list); 226 227 assertEquals("Ordering.arbitrary()", arbitrary.toString()); 228 } 229 230 public void testArbitrary_withCollisions() { 231 List<Integer> list = Lists.newArrayList(); 232 for (int i = 0; i < 50; i++) { 233 list.add(i); 234 } 235 236 Ordering<Object> arbitrary = 237 new ArbitraryOrdering() { 238 @Override 239 int identityHashCode(Object object) { 240 return ((Integer) object) % 5; // fake tons of collisions! 241 } 242 }; 243 244 // Don't let the elements be in such a predictable order 245 list = shuffledCopy(list, new Random(1)); 246 247 Collections.sort(list, arbitrary); 248 249 // Now we don't care what order it's put the list in, only that 250 // comparing any pair of elements gives the answer we expect. 251 Helpers.testComparator(arbitrary, list); 252 } 253 254 public void testUsingToString() { 255 Ordering<Object> ordering = Ordering.usingToString(); 256 Helpers.testComparator(ordering, 1, 12, 124, 2); 257 assertEquals("Ordering.usingToString()", ordering.toString()); 258 assertSame(ordering, reserialize(ordering)); 259 } 260 261 // use an enum to get easy serializability 262 private enum CharAtFunction implements Function<String, Character> { 263 AT0(0), 264 AT1(1), 265 AT2(2), 266 AT3(3), 267 AT4(4), 268 AT5(5), 269 ; 270 271 final int index; 272 273 CharAtFunction(int index) { 274 this.index = index; 275 } 276 277 @Override 278 public Character apply(String string) { 279 return string.charAt(index); 280 } 281 } 282 283 private static Ordering<String> byCharAt(int index) { 284 return Ordering.natural().onResultOf(CharAtFunction.values()[index]); 285 } 286 287 public void testCompound_static() { 288 Comparator<String> comparator = 289 Ordering.compound( 290 ImmutableList.of( 291 byCharAt(0), byCharAt(1), byCharAt(2), byCharAt(3), byCharAt(4), byCharAt(5))); 292 Helpers.testComparator( 293 comparator, 294 ImmutableList.of( 295 "applesauce", 296 "apricot", 297 "artichoke", 298 "banality", 299 "banana", 300 "banquet", 301 "tangelo", 302 "tangerine")); 303 reserializeAndAssert(comparator); 304 } 305 306 public void testCompound_instance() { 307 Comparator<String> comparator = byCharAt(1).compound(byCharAt(0)); 308 Helpers.testComparator( 309 comparator, 310 ImmutableList.of("red", "yellow", "violet", "blue", "indigo", "green", "orange")); 311 } 312 313 public void testCompound_instance_generics() { 314 Ordering<Object> objects = Ordering.explicit((Object) 1); 315 Ordering<Number> numbers = Ordering.explicit((Number) 1); 316 Ordering<Integer> integers = Ordering.explicit(1); 317 318 // Like by like equals like 319 Ordering<Number> a = numbers.compound(numbers); 320 321 // The compound takes the more specific type of the two, regardless of order 322 323 Ordering<Number> b = numbers.compound(objects); 324 Ordering<Number> c = objects.compound(numbers); 325 326 Ordering<Integer> d = numbers.compound(integers); 327 Ordering<Integer> e = integers.compound(numbers); 328 329 // This works with three levels too (IDEA falsely reports errors as noted 330 // below. Both javac and eclipse handle these cases correctly.) 331 332 Ordering<Number> f = numbers.compound(objects).compound(objects); // bad IDEA 333 Ordering<Number> g = objects.compound(numbers).compound(objects); 334 Ordering<Number> h = objects.compound(objects).compound(numbers); 335 336 Ordering<Number> i = numbers.compound(objects.compound(objects)); 337 Ordering<Number> j = objects.compound(numbers.compound(objects)); // bad IDEA 338 Ordering<Number> k = objects.compound(objects.compound(numbers)); 339 340 // You can also arbitrarily assign a more restricted type - not an intended 341 // feature, exactly, but unavoidable (I think) and harmless 342 Ordering<Integer> l = objects.compound(numbers); 343 344 // This correctly doesn't work: 345 // Ordering<Object> m = numbers.compound(objects); 346 347 // Sadly, the following works in javac 1.6, but at least it fails for 348 // eclipse, and is *correctly* highlighted red in IDEA. 349 // Ordering<Object> n = objects.compound(numbers); 350 } 351 352 public void testReverse() { 353 Ordering<Number> reverseOrder = numberOrdering.reverse(); 354 Helpers.testComparator(reverseOrder, Integer.MAX_VALUE, 1, 0, -1, Integer.MIN_VALUE); 355 356 new EqualsTester() 357 .addEqualityGroup(reverseOrder, numberOrdering.reverse()) 358 .addEqualityGroup(Ordering.natural().reverse()) 359 .addEqualityGroup(Collections.reverseOrder()) 360 .testEquals(); 361 } 362 363 public void testReverseOfReverseSameAsForward() { 364 // Not guaranteed by spec, but it works, and saves us from testing 365 // exhaustively 366 assertSame(numberOrdering, numberOrdering.reverse().reverse()); 367 } 368 369 private enum StringLengthFunction implements Function<String, Integer> { 370 StringLength; 371 372 @Override 373 public Integer apply(String string) { 374 return string.length(); 375 } 376 } 377 378 private static final Ordering<Integer> DECREASING_INTEGER = Ordering.natural().reverse(); 379 380 public void testOnResultOf_natural() { 381 Comparator<String> comparator = 382 Ordering.natural().onResultOf(StringLengthFunction.StringLength); 383 assertTrue(comparator.compare("to", "be") == 0); 384 assertTrue(comparator.compare("or", "not") < 0); 385 assertTrue(comparator.compare("that", "to") > 0); 386 387 new EqualsTester() 388 .addEqualityGroup( 389 comparator, Ordering.natural().onResultOf(StringLengthFunction.StringLength)) 390 .addEqualityGroup(DECREASING_INTEGER) 391 .testEquals(); 392 reserializeAndAssert(comparator); 393 assertEquals("Ordering.natural().onResultOf(StringLength)", comparator.toString()); 394 } 395 396 public void testOnResultOf_chained() { 397 Comparator<String> comparator = 398 DECREASING_INTEGER.onResultOf(StringLengthFunction.StringLength); 399 assertTrue(comparator.compare("to", "be") == 0); 400 assertTrue(comparator.compare("not", "or") < 0); 401 assertTrue(comparator.compare("to", "that") > 0); 402 403 new EqualsTester() 404 .addEqualityGroup( 405 comparator, DECREASING_INTEGER.onResultOf(StringLengthFunction.StringLength)) 406 .addEqualityGroup(DECREASING_INTEGER.onResultOf(Functions.constant(1))) 407 .addEqualityGroup(Ordering.natural()) 408 .testEquals(); 409 reserializeAndAssert(comparator); 410 assertEquals("Ordering.natural().reverse().onResultOf(StringLength)", comparator.toString()); 411 } 412 413 @SuppressWarnings("unchecked") // dang varargs 414 public void testLexicographical() { 415 Ordering<String> ordering = Ordering.natural(); 416 Ordering<Iterable<String>> lexy = ordering.lexicographical(); 417 418 ImmutableList<String> empty = ImmutableList.of(); 419 ImmutableList<String> a = ImmutableList.of("a"); 420 ImmutableList<String> aa = ImmutableList.of("a", "a"); 421 ImmutableList<String> ab = ImmutableList.of("a", "b"); 422 ImmutableList<String> b = ImmutableList.of("b"); 423 424 Helpers.testComparator(lexy, empty, a, aa, ab, b); 425 426 new EqualsTester() 427 .addEqualityGroup(lexy, ordering.lexicographical()) 428 .addEqualityGroup(numberOrdering.lexicographical()) 429 .addEqualityGroup(Ordering.natural()) 430 .testEquals(); 431 } 432 433 public void testNullsFirst() { 434 Ordering<Integer> ordering = Ordering.natural().nullsFirst(); 435 Helpers.testComparator(ordering, null, Integer.MIN_VALUE, 0, 1); 436 437 new EqualsTester() 438 .addEqualityGroup(ordering, Ordering.natural().nullsFirst()) 439 .addEqualityGroup(numberOrdering.nullsFirst()) 440 .addEqualityGroup(Ordering.natural()) 441 .testEquals(); 442 } 443 444 public void testNullsLast() { 445 Ordering<Integer> ordering = Ordering.natural().nullsLast(); 446 Helpers.testComparator(ordering, 0, 1, Integer.MAX_VALUE, null); 447 448 new EqualsTester() 449 .addEqualityGroup(ordering, Ordering.natural().nullsLast()) 450 .addEqualityGroup(numberOrdering.nullsLast()) 451 .addEqualityGroup(Ordering.natural()) 452 .testEquals(); 453 } 454 455 public void testBinarySearch() { 456 List<Integer> ints = Lists.newArrayList(0, 2, 3, 5, 7, 9); 457 assertEquals(4, numberOrdering.binarySearch(ints, 7)); 458 } 459 460 public void testSortedCopy() { 461 List<Integer> unsortedInts = Collections.unmodifiableList(Arrays.asList(5, 0, 3, null, 0, 9)); 462 List<Integer> sortedInts = numberOrdering.nullsLast().sortedCopy(unsortedInts); 463 assertEquals(Arrays.asList(0, 0, 3, 5, 9, null), sortedInts); 464 465 assertEquals( 466 Collections.emptyList(), numberOrdering.sortedCopy(Collections.<Integer>emptyList())); 467 } 468 469 public void testImmutableSortedCopy() { 470 ImmutableList<Integer> unsortedInts = ImmutableList.of(5, 3, 0, 9, 3); 471 ImmutableList<Integer> sortedInts = numberOrdering.immutableSortedCopy(unsortedInts); 472 assertEquals(Arrays.asList(0, 3, 3, 5, 9), sortedInts); 473 474 assertEquals( 475 Collections.<Integer>emptyList(), 476 numberOrdering.immutableSortedCopy(Collections.<Integer>emptyList())); 477 478 List<Integer> listWithNull = Arrays.asList(5, 3, null, 9); 479 try { 480 Ordering.natural().nullsFirst().immutableSortedCopy(listWithNull); 481 fail(); 482 } catch (NullPointerException expected) { 483 } 484 } 485 486 public void testIsOrdered() { 487 assertFalse(numberOrdering.isOrdered(asList(5, 3, 0, 9))); 488 assertFalse(numberOrdering.isOrdered(asList(0, 5, 3, 9))); 489 assertTrue(numberOrdering.isOrdered(asList(0, 3, 5, 9))); 490 assertTrue(numberOrdering.isOrdered(asList(0, 0, 3, 3))); 491 assertTrue(numberOrdering.isOrdered(asList(0, 3))); 492 assertTrue(numberOrdering.isOrdered(Collections.singleton(1))); 493 assertTrue(numberOrdering.isOrdered(Collections.<Integer>emptyList())); 494 } 495 496 public void testIsStrictlyOrdered() { 497 assertFalse(numberOrdering.isStrictlyOrdered(asList(5, 3, 0, 9))); 498 assertFalse(numberOrdering.isStrictlyOrdered(asList(0, 5, 3, 9))); 499 assertTrue(numberOrdering.isStrictlyOrdered(asList(0, 3, 5, 9))); 500 assertFalse(numberOrdering.isStrictlyOrdered(asList(0, 0, 3, 3))); 501 assertTrue(numberOrdering.isStrictlyOrdered(asList(0, 3))); 502 assertTrue(numberOrdering.isStrictlyOrdered(Collections.singleton(1))); 503 assertTrue(numberOrdering.isStrictlyOrdered(Collections.<Integer>emptyList())); 504 } 505 506 public void testLeastOfIterable_empty_0() { 507 List<Integer> result = numberOrdering.leastOf(Arrays.<Integer>asList(), 0); 508 assertTrue(result instanceof RandomAccess); 509 assertListImmutable(result); 510 assertEquals(ImmutableList.<Integer>of(), result); 511 } 512 513 public void testLeastOfIterator_empty_0() { 514 List<Integer> result = numberOrdering.leastOf(Iterators.<Integer>emptyIterator(), 0); 515 assertTrue(result instanceof RandomAccess); 516 assertListImmutable(result); 517 assertEquals(ImmutableList.<Integer>of(), result); 518 } 519 520 public void testLeastOfIterable_empty_1() { 521 List<Integer> result = numberOrdering.leastOf(Arrays.<Integer>asList(), 1); 522 assertTrue(result instanceof RandomAccess); 523 assertListImmutable(result); 524 assertEquals(ImmutableList.<Integer>of(), result); 525 } 526 527 public void testLeastOfIterator_empty_1() { 528 List<Integer> result = numberOrdering.leastOf(Iterators.<Integer>emptyIterator(), 1); 529 assertTrue(result instanceof RandomAccess); 530 assertListImmutable(result); 531 assertEquals(ImmutableList.<Integer>of(), result); 532 } 533 534 public void testLeastOfIterable_simple_negativeOne() { 535 try { 536 numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), -1); 537 fail(); 538 } catch (IllegalArgumentException expected) { 539 } 540 } 541 542 public void testLeastOfIterator_simple_negativeOne() { 543 try { 544 numberOrdering.leastOf(Iterators.forArray(3, 4, 5, -1), -1); 545 fail(); 546 } catch (IllegalArgumentException expected) { 547 } 548 } 549 550 public void testLeastOfIterable_singleton_0() { 551 List<Integer> result = numberOrdering.leastOf(Arrays.asList(3), 0); 552 assertTrue(result instanceof RandomAccess); 553 assertListImmutable(result); 554 assertEquals(ImmutableList.<Integer>of(), result); 555 } 556 557 public void testLeastOfIterator_singleton_0() { 558 List<Integer> result = numberOrdering.leastOf(Iterators.singletonIterator(3), 0); 559 assertTrue(result instanceof RandomAccess); 560 assertListImmutable(result); 561 assertEquals(ImmutableList.<Integer>of(), result); 562 } 563 564 public void testLeastOfIterable_simple_0() { 565 List<Integer> result = numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), 0); 566 assertTrue(result instanceof RandomAccess); 567 assertListImmutable(result); 568 assertEquals(ImmutableList.<Integer>of(), result); 569 } 570 571 public void testLeastOfIterator_simple_0() { 572 List<Integer> result = numberOrdering.leastOf(Iterators.forArray(3, 4, 5, -1), 0); 573 assertTrue(result instanceof RandomAccess); 574 assertListImmutable(result); 575 assertEquals(ImmutableList.<Integer>of(), result); 576 } 577 578 public void testLeastOfIterable_simple_1() { 579 List<Integer> result = numberOrdering.leastOf(Arrays.asList(3, 4, 5, -1), 1); 580 assertTrue(result instanceof RandomAccess); 581 assertListImmutable(result); 582 assertEquals(ImmutableList.of(-1), result); 583 } 584 585 public void testLeastOfIterator_simple_1() { 586 List<Integer> result = numberOrdering.leastOf(Iterators.forArray(3, 4, 5, -1), 1); 587 assertTrue(result instanceof RandomAccess); 588 assertListImmutable(result); 589 assertEquals(ImmutableList.of(-1), result); 590 } 591 592 public void testLeastOfIterable_simple_nMinusOne_withNullElement() { 593 List<Integer> list = Arrays.asList(3, null, 5, -1); 594 List<Integer> result = Ordering.natural().nullsLast().leastOf(list, list.size() - 1); 595 assertTrue(result instanceof RandomAccess); 596 assertListImmutable(result); 597 assertEquals(ImmutableList.of(-1, 3, 5), result); 598 } 599 600 public void testLeastOfIterator_simple_nMinusOne_withNullElement() { 601 Iterator<Integer> itr = Iterators.forArray(3, null, 5, -1); 602 List<Integer> result = Ordering.natural().nullsLast().leastOf(itr, 3); 603 assertTrue(result instanceof RandomAccess); 604 assertListImmutable(result); 605 assertEquals(ImmutableList.of(-1, 3, 5), result); 606 } 607 608 public void testLeastOfIterable_simple_nMinusOne() { 609 List<Integer> list = Arrays.asList(3, 4, 5, -1); 610 List<Integer> result = numberOrdering.leastOf(list, list.size() - 1); 611 assertTrue(result instanceof RandomAccess); 612 assertListImmutable(result); 613 assertEquals(ImmutableList.of(-1, 3, 4), result); 614 } 615 616 public void testLeastOfIterator_simple_nMinusOne() { 617 List<Integer> list = Arrays.asList(3, 4, 5, -1); 618 List<Integer> result = numberOrdering.leastOf(list.iterator(), list.size() - 1); 619 assertTrue(result instanceof RandomAccess); 620 assertListImmutable(result); 621 assertEquals(ImmutableList.of(-1, 3, 4), result); 622 } 623 624 public void testLeastOfIterable_simple_n() { 625 List<Integer> list = Arrays.asList(3, 4, 5, -1); 626 List<Integer> result = numberOrdering.leastOf(list, list.size()); 627 assertTrue(result instanceof RandomAccess); 628 assertListImmutable(result); 629 assertEquals(ImmutableList.of(-1, 3, 4, 5), result); 630 } 631 632 public void testLeastOfIterator_simple_n() { 633 List<Integer> list = Arrays.asList(3, 4, 5, -1); 634 List<Integer> result = numberOrdering.leastOf(list.iterator(), list.size()); 635 assertTrue(result instanceof RandomAccess); 636 assertListImmutable(result); 637 assertEquals(ImmutableList.of(-1, 3, 4, 5), result); 638 } 639 640 public void testLeastOfIterable_simple_n_withNullElement() { 641 List<Integer> list = Arrays.asList(3, 4, 5, null, -1); 642 List<Integer> result = Ordering.natural().nullsLast().leastOf(list, list.size()); 643 assertTrue(result instanceof RandomAccess); 644 assertListImmutable(result); 645 assertEquals(Arrays.asList(-1, 3, 4, 5, null), result); 646 } 647 648 public void testLeastOfIterator_simple_n_withNullElement() { 649 List<Integer> list = Arrays.asList(3, 4, 5, null, -1); 650 List<Integer> result = Ordering.natural().nullsLast().leastOf(list.iterator(), list.size()); 651 assertTrue(result instanceof RandomAccess); 652 assertListImmutable(result); 653 assertEquals(Arrays.asList(-1, 3, 4, 5, null), result); 654 } 655 656 public void testLeastOfIterable_simple_nPlusOne() { 657 List<Integer> list = Arrays.asList(3, 4, 5, -1); 658 List<Integer> result = numberOrdering.leastOf(list, list.size() + 1); 659 assertTrue(result instanceof RandomAccess); 660 assertListImmutable(result); 661 assertEquals(ImmutableList.of(-1, 3, 4, 5), result); 662 } 663 664 public void testLeastOfIterator_simple_nPlusOne() { 665 List<Integer> list = Arrays.asList(3, 4, 5, -1); 666 List<Integer> result = numberOrdering.leastOf(list.iterator(), list.size() + 1); 667 assertTrue(result instanceof RandomAccess); 668 assertListImmutable(result); 669 assertEquals(ImmutableList.of(-1, 3, 4, 5), result); 670 } 671 672 public void testLeastOfIterable_ties() { 673 Integer foo = new Integer(Integer.MAX_VALUE - 10); 674 Integer bar = new Integer(Integer.MAX_VALUE - 10); 675 676 assertNotSame(foo, bar); 677 assertEquals(foo, bar); 678 679 List<Integer> list = Arrays.asList(3, foo, bar, -1); 680 List<Integer> result = numberOrdering.leastOf(list, list.size()); 681 assertEquals(ImmutableList.of(-1, 3, foo, bar), result); 682 } 683 684 public void testLeastOfIterator_ties() { 685 Integer foo = new Integer(Integer.MAX_VALUE - 10); 686 Integer bar = new Integer(Integer.MAX_VALUE - 10); 687 688 assertNotSame(foo, bar); 689 assertEquals(foo, bar); 690 691 List<Integer> list = Arrays.asList(3, foo, bar, -1); 692 List<Integer> result = numberOrdering.leastOf(list.iterator(), list.size()); 693 assertEquals(ImmutableList.of(-1, 3, foo, bar), result); 694 } 695 696 @GwtIncompatible // slow 697 public void testLeastOf_reconcileAgainstSortAndSublist() { 698 runLeastOfComparison(1000, 300, 20); 699 } 700 701 public void testLeastOf_reconcileAgainstSortAndSublistSmall() { 702 runLeastOfComparison(10, 30, 2); 703 } 704 705 private static void runLeastOfComparison(int iterations, int elements, int seeds) { 706 Random random = new Random(42); 707 Ordering<Integer> ordering = Ordering.natural(); 708 709 for (int i = 0; i < iterations; i++) { 710 List<Integer> list = Lists.newArrayList(); 711 for (int j = 0; j < elements; j++) { 712 list.add(random.nextInt(10 * i + j + 1)); 713 } 714 715 for (int seed = 1; seed < seeds; seed++) { 716 int k = random.nextInt(10 * seed); 717 assertEquals(ordering.sortedCopy(list).subList(0, k), ordering.leastOf(list, k)); 718 } 719 } 720 } 721 722 public void testLeastOfIterableLargeK() { 723 List<Integer> list = Arrays.asList(4, 2, 3, 5, 1); 724 assertEquals(Arrays.asList(1, 2, 3, 4, 5), Ordering.natural().leastOf(list, Integer.MAX_VALUE)); 725 } 726 727 public void testLeastOfIteratorLargeK() { 728 List<Integer> list = Arrays.asList(4, 2, 3, 5, 1); 729 assertEquals( 730 Arrays.asList(1, 2, 3, 4, 5), 731 Ordering.natural().leastOf(list.iterator(), Integer.MAX_VALUE)); 732 } 733 734 public void testGreatestOfIterable_simple() { 735 /* 736 * If greatestOf() promised to be implemented as reverse().leastOf(), this 737 * test would be enough. It doesn't... but we'll cheat and act like it does 738 * anyway. There's a comment there to remind us to fix this if we change it. 739 */ 740 List<Integer> list = Arrays.asList(3, 1, 3, 2, 4, 2, 4, 3); 741 assertEquals(Arrays.asList(4, 4, 3, 3), numberOrdering.greatestOf(list, 4)); 742 } 743 744 public void testGreatestOfIterator_simple() { 745 /* 746 * If greatestOf() promised to be implemented as reverse().leastOf(), this 747 * test would be enough. It doesn't... but we'll cheat and act like it does 748 * anyway. There's a comment there to remind us to fix this if we change it. 749 */ 750 List<Integer> list = Arrays.asList(3, 1, 3, 2, 4, 2, 4, 3); 751 assertEquals(Arrays.asList(4, 4, 3, 3), numberOrdering.greatestOf(list.iterator(), 4)); 752 } 753 754 private static void assertListImmutable(List<Integer> result) { 755 try { 756 result.set(0, 1); 757 fail(); 758 } catch (UnsupportedOperationException expected) { 759 // pass 760 } 761 } 762 763 public void testIteratorMinAndMax() { 764 List<Integer> ints = Lists.newArrayList(5, 3, 0, 9); 765 assertEquals(9, (int) numberOrdering.max(ints.iterator())); 766 assertEquals(0, (int) numberOrdering.min(ints.iterator())); 767 768 // when the values are the same, the first argument should be returned 769 Integer a = new Integer(4); 770 Integer b = new Integer(4); 771 ints = Lists.newArrayList(a, b, b); 772 assertSame(a, numberOrdering.max(ints.iterator())); 773 assertSame(a, numberOrdering.min(ints.iterator())); 774 } 775 776 public void testIteratorMinExhaustsIterator() { 777 List<Integer> ints = Lists.newArrayList(9, 0, 3, 5); 778 Iterator<Integer> iterator = ints.iterator(); 779 assertEquals(0, (int) numberOrdering.min(iterator)); 780 assertFalse(iterator.hasNext()); 781 } 782 783 public void testIteratorMaxExhaustsIterator() { 784 List<Integer> ints = Lists.newArrayList(9, 0, 3, 5); 785 Iterator<Integer> iterator = ints.iterator(); 786 assertEquals(9, (int) numberOrdering.max(iterator)); 787 assertFalse(iterator.hasNext()); 788 } 789 790 public void testIterableMinAndMax() { 791 List<Integer> ints = Lists.newArrayList(5, 3, 0, 9); 792 assertEquals(9, (int) numberOrdering.max(ints)); 793 assertEquals(0, (int) numberOrdering.min(ints)); 794 795 // when the values are the same, the first argument should be returned 796 Integer a = new Integer(4); 797 Integer b = new Integer(4); 798 ints = Lists.newArrayList(a, b, b); 799 assertSame(a, numberOrdering.max(ints)); 800 assertSame(a, numberOrdering.min(ints)); 801 } 802 803 public void testVarargsMinAndMax() { 804 // try the min and max values in all positions, since some values are proper 805 // parameters and others are from the varargs array 806 assertEquals(9, (int) numberOrdering.max(9, 3, 0, 5, 8)); 807 assertEquals(9, (int) numberOrdering.max(5, 9, 0, 3, 8)); 808 assertEquals(9, (int) numberOrdering.max(5, 3, 9, 0, 8)); 809 assertEquals(9, (int) numberOrdering.max(5, 3, 0, 9, 8)); 810 assertEquals(9, (int) numberOrdering.max(5, 3, 0, 8, 9)); 811 assertEquals(0, (int) numberOrdering.min(0, 3, 5, 9, 8)); 812 assertEquals(0, (int) numberOrdering.min(5, 0, 3, 9, 8)); 813 assertEquals(0, (int) numberOrdering.min(5, 3, 0, 9, 8)); 814 assertEquals(0, (int) numberOrdering.min(5, 3, 9, 0, 8)); 815 assertEquals(0, (int) numberOrdering.min(5, 3, 0, 9, 0)); 816 817 // when the values are the same, the first argument should be returned 818 Integer a = new Integer(4); 819 Integer b = new Integer(4); 820 assertSame(a, numberOrdering.max(a, b, b)); 821 assertSame(a, numberOrdering.min(a, b, b)); 822 } 823 824 public void testParameterMinAndMax() { 825 assertEquals(5, (int) numberOrdering.max(3, 5)); 826 assertEquals(5, (int) numberOrdering.max(5, 3)); 827 assertEquals(3, (int) numberOrdering.min(3, 5)); 828 assertEquals(3, (int) numberOrdering.min(5, 3)); 829 830 // when the values are the same, the first argument should be returned 831 Integer a = new Integer(4); 832 Integer b = new Integer(4); 833 assertSame(a, numberOrdering.max(a, b)); 834 assertSame(a, numberOrdering.min(a, b)); 835 } 836 837 private static class NumberOrdering extends Ordering<Number> { 838 @Override 839 public int compare(Number a, Number b) { 840 return ((Double) a.doubleValue()).compareTo(b.doubleValue()); 841 } 842 843 @Override 844 public int hashCode() { 845 return NumberOrdering.class.hashCode(); 846 } 847 848 @Override 849 public boolean equals(@Nullable Object other) { 850 return other instanceof NumberOrdering; 851 } 852 853 private static final long serialVersionUID = 0; 854 } 855 856 /* 857 * Now we have monster tests that create hundreds of Orderings using different 858 * combinations of methods, then checks compare(), binarySearch() and so 859 * forth on each one. 860 */ 861 862 // should periodically try increasing this, but it makes the test run long 863 private static final int RECURSE_DEPTH = 2; 864 865 public void testCombinationsExhaustively_startingFromNatural() { 866 testExhaustively(Ordering.<String>natural(), "a", "b", "d"); 867 } 868 869 @GwtIncompatible // too slow 870 public void testCombinationsExhaustively_startingFromExplicit() { 871 testExhaustively(Ordering.explicit("a", "b", "c", "d"), "a", "b", "d"); 872 } 873 874 @GwtIncompatible // too slow 875 public void testCombinationsExhaustively_startingFromUsingToString() { 876 testExhaustively(Ordering.usingToString(), 1, 12, 2); 877 } 878 879 @GwtIncompatible // too slow 880 public void testCombinationsExhaustively_startingFromFromComparator() { 881 testExhaustively(Ordering.from(String.CASE_INSENSITIVE_ORDER), "A", "b", "C", "d"); 882 } 883 884 @GwtIncompatible // too slow 885 public void testCombinationsExhaustively_startingFromArbitrary() { 886 Ordering<Object> arbitrary = Ordering.arbitrary(); 887 Object[] array = {1, "foo", new Object()}; 888 889 // There's no way to tell what the order should be except empirically 890 Arrays.sort(array, arbitrary); 891 testExhaustively(arbitrary, array); 892 } 893 894 /** 895 * Requires at least 3 elements in {@code strictlyOrderedElements} in order to test the varargs 896 * version of min/max. 897 */ 898 private static <T> void testExhaustively( 899 Ordering<? super T> ordering, T... strictlyOrderedElements) { 900 checkArgument( 901 strictlyOrderedElements.length >= 3, 902 "strictlyOrderedElements " + "requires at least 3 elements"); 903 List<T> list = Arrays.asList(strictlyOrderedElements); 904 905 // for use calling Collection.toArray later 906 T[] emptyArray = Platform.newArray(strictlyOrderedElements, 0); 907 908 // shoot me, but I didn't want to deal with wildcards through the whole test 909 @SuppressWarnings("unchecked") 910 Scenario<T> starter = new Scenario<>((Ordering) ordering, list, emptyArray); 911 verifyScenario(starter, 0); 912 } 913 914 private static <T> void verifyScenario(Scenario<T> scenario, int level) { 915 scenario.testCompareTo(); 916 scenario.testIsOrdered(); 917 scenario.testMinAndMax(); 918 scenario.testBinarySearch(); 919 scenario.testSortedCopy(); 920 921 if (level < RECURSE_DEPTH) { 922 for (OrderingMutation alteration : OrderingMutation.values()) { 923 verifyScenario(alteration.mutate(scenario), level + 1); 924 } 925 } 926 } 927 928 /** 929 * An aggregation of an ordering with a list (of size > 1) that should prove to be in strictly 930 * increasing order according to that ordering. 931 */ 932 private static class Scenario<T> { 933 final Ordering<T> ordering; 934 final List<T> strictlyOrderedList; 935 final T[] emptyArray; 936 937 Scenario(Ordering<T> ordering, List<T> strictlyOrderedList, T[] emptyArray) { 938 this.ordering = ordering; 939 this.strictlyOrderedList = strictlyOrderedList; 940 this.emptyArray = emptyArray; 941 } 942 943 void testCompareTo() { 944 Helpers.testComparator(ordering, strictlyOrderedList); 945 } 946 947 void testIsOrdered() { 948 assertTrue(ordering.isOrdered(strictlyOrderedList)); 949 assertTrue(ordering.isStrictlyOrdered(strictlyOrderedList)); 950 } 951 952 @SuppressWarnings("unchecked") // generic arrays and unchecked cast 953 void testMinAndMax() { 954 List<T> shuffledList = Lists.newArrayList(strictlyOrderedList); 955 shuffledList = shuffledCopy(shuffledList, new Random(5)); 956 957 T min = strictlyOrderedList.get(0); 958 T max = strictlyOrderedList.get(strictlyOrderedList.size() - 1); 959 960 T first = shuffledList.get(0); 961 T second = shuffledList.get(1); 962 T third = shuffledList.get(2); 963 T[] rest = shuffledList.subList(3, shuffledList.size()).toArray(emptyArray); 964 965 assertEquals(min, ordering.min(shuffledList)); 966 assertEquals(min, ordering.min(shuffledList.iterator())); 967 assertEquals(min, ordering.min(first, second, third, rest)); 968 assertEquals(min, ordering.min(min, max)); 969 assertEquals(min, ordering.min(max, min)); 970 971 assertEquals(max, ordering.max(shuffledList)); 972 assertEquals(max, ordering.max(shuffledList.iterator())); 973 assertEquals(max, ordering.max(first, second, third, rest)); 974 assertEquals(max, ordering.max(min, max)); 975 assertEquals(max, ordering.max(max, min)); 976 } 977 978 void testBinarySearch() { 979 for (int i = 0; i < strictlyOrderedList.size(); i++) { 980 assertEquals(i, ordering.binarySearch(strictlyOrderedList, strictlyOrderedList.get(i))); 981 } 982 List<T> newList = Lists.newArrayList(strictlyOrderedList); 983 T valueNotInList = newList.remove(1); 984 assertEquals(-2, ordering.binarySearch(newList, valueNotInList)); 985 } 986 987 void testSortedCopy() { 988 List<T> shuffledList = Lists.newArrayList(strictlyOrderedList); 989 shuffledList = shuffledCopy(shuffledList, new Random(5)); 990 991 assertEquals(strictlyOrderedList, ordering.sortedCopy(shuffledList)); 992 993 if (!strictlyOrderedList.contains(null)) { 994 assertEquals(strictlyOrderedList, ordering.immutableSortedCopy(shuffledList)); 995 } 996 } 997 } 998 999 /** 1000 * A means for changing an Ordering into another Ordering. Each instance is responsible for 1001 * creating the alternate Ordering, and providing a List that is known to be ordered, based on an 1002 * input List known to be ordered according to the input Ordering. 1003 */ 1004 private enum OrderingMutation { 1005 REVERSE { 1006 @Override 1007 <T> Scenario<?> mutate(Scenario<T> scenario) { 1008 List<T> newList = Lists.newArrayList(scenario.strictlyOrderedList); 1009 Collections.reverse(newList); 1010 return new Scenario<T>(scenario.ordering.reverse(), newList, scenario.emptyArray); 1011 } 1012 }, 1013 NULLS_FIRST { 1014 @Override 1015 <T> Scenario<?> mutate(Scenario<T> scenario) { 1016 @SuppressWarnings("unchecked") 1017 List<T> newList = Lists.newArrayList((T) null); 1018 for (T t : scenario.strictlyOrderedList) { 1019 if (t != null) { 1020 newList.add(t); 1021 } 1022 } 1023 return new Scenario<T>(scenario.ordering.nullsFirst(), newList, scenario.emptyArray); 1024 } 1025 }, 1026 NULLS_LAST { 1027 @Override 1028 <T> Scenario<?> mutate(Scenario<T> scenario) { 1029 List<T> newList = Lists.newArrayList(); 1030 for (T t : scenario.strictlyOrderedList) { 1031 if (t != null) { 1032 newList.add(t); 1033 } 1034 } 1035 newList.add(null); 1036 return new Scenario<T>(scenario.ordering.nullsLast(), newList, scenario.emptyArray); 1037 } 1038 }, 1039 ON_RESULT_OF { 1040 @Override 1041 <T> Scenario<?> mutate(final Scenario<T> scenario) { 1042 Ordering<Integer> ordering = 1043 scenario.ordering.onResultOf( 1044 new Function<Integer, T>() { 1045 @Override 1046 public T apply(@Nullable Integer from) { 1047 return scenario.strictlyOrderedList.get(from); 1048 } 1049 }); 1050 List<Integer> list = Lists.newArrayList(); 1051 for (int i = 0; i < scenario.strictlyOrderedList.size(); i++) { 1052 list.add(i); 1053 } 1054 return new Scenario<>(ordering, list, new Integer[0]); 1055 } 1056 }, 1057 COMPOUND_THIS_WITH_NATURAL { 1058 @SuppressWarnings("unchecked") // raw array 1059 @Override 1060 <T> Scenario<?> mutate(Scenario<T> scenario) { 1061 List<Composite<T>> composites = Lists.newArrayList(); 1062 for (T t : scenario.strictlyOrderedList) { 1063 composites.add(new Composite<T>(t, 1)); 1064 composites.add(new Composite<T>(t, 2)); 1065 } 1066 Ordering<Composite<T>> ordering = 1067 scenario 1068 .ordering 1069 .onResultOf(Composite.<T>getValueFunction()) 1070 .compound(Ordering.natural()); 1071 return new Scenario<Composite<T>>(ordering, composites, new Composite[0]); 1072 } 1073 }, 1074 COMPOUND_NATURAL_WITH_THIS { 1075 @SuppressWarnings("unchecked") // raw array 1076 @Override 1077 <T> Scenario<?> mutate(Scenario<T> scenario) { 1078 List<Composite<T>> composites = Lists.newArrayList(); 1079 for (T t : scenario.strictlyOrderedList) { 1080 composites.add(new Composite<T>(t, 1)); 1081 } 1082 for (T t : scenario.strictlyOrderedList) { 1083 composites.add(new Composite<T>(t, 2)); 1084 } 1085 Ordering<Composite<T>> ordering = 1086 Ordering.natural() 1087 .compound(scenario.ordering.onResultOf(Composite.<T>getValueFunction())); 1088 return new Scenario<Composite<T>>(ordering, composites, new Composite[0]); 1089 } 1090 }, 1091 LEXICOGRAPHICAL { 1092 @SuppressWarnings("unchecked") // dang varargs 1093 @Override 1094 <T> Scenario<?> mutate(Scenario<T> scenario) { 1095 List<Iterable<T>> words = Lists.newArrayList(); 1096 words.add(Collections.<T>emptyList()); 1097 for (T t : scenario.strictlyOrderedList) { 1098 words.add(Arrays.asList(t)); 1099 for (T s : scenario.strictlyOrderedList) { 1100 words.add(Arrays.asList(t, s)); 1101 } 1102 } 1103 return new Scenario<Iterable<T>>( 1104 scenario.ordering.lexicographical(), words, new Iterable[0]); 1105 } 1106 }, 1107 ; 1108 1109 abstract <T> Scenario<?> mutate(Scenario<T> scenario); 1110 } 1111 1112 /** 1113 * A dummy object we create so that we can have something meaningful to have a compound ordering 1114 * over. 1115 */ 1116 private static class Composite<T> implements Comparable<Composite<T>> { 1117 final T value; 1118 final int rank; 1119 1120 Composite(T value, int rank) { 1121 this.value = value; 1122 this.rank = rank; 1123 } 1124 1125 // natural order is by rank only; the test will compound() this with the 1126 // order of 't'. 1127 @Override 1128 public int compareTo(Composite<T> that) { 1129 return Ints.compare(rank, that.rank); 1130 } 1131 1132 static <T> Function<Composite<T>, T> getValueFunction() { 1133 return new Function<Composite<T>, T>() { 1134 @Override 1135 public T apply(Composite<T> from) { 1136 return from.value; 1137 } 1138 }; 1139 } 1140 } 1141 1142 @GwtIncompatible // NullPointerTester 1143 public void testNullPointerExceptions() { 1144 NullPointerTester tester = new NullPointerTester(); 1145 tester.testAllPublicStaticMethods(Ordering.class); 1146 1147 // any Ordering<Object> instance that accepts nulls should be good enough 1148 tester.testAllPublicInstanceMethods(Ordering.usingToString().nullsFirst()); 1149 } 1150 1151 private static <T> List<T> shuffledCopy(List<T> in, Random random) { 1152 List<T> mutable = newArrayList(in); 1153 List<T> out = newArrayList(); 1154 while (!mutable.isEmpty()) { 1155 out.add(mutable.remove(random.nextInt(mutable.size()))); 1156 } 1157 return out; 1158 } 1159 } 1160