| /* | |
| * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /** | |
| * @test | |
| * @bug 8171826 | |
| * @summary Comparator default method tests | |
| * @run testng BasicTest | |
| */ | |
| import org.testng.annotations.Test; | |
| import java.util.Collections; | |
| import java.util.Comparator; | |
| import java.util.function.Function; | |
| import java.util.function.ToDoubleFunction; | |
| import java.util.function.ToIntFunction; | |
| import java.util.function.ToLongFunction; | |
| import static org.testng.Assert.*; | |
| @Test(groups = "unit") | |
| public class BasicTest { | |
| private static class Thing { | |
| public final int intField; | |
| public final long longField; | |
| public final double doubleField; | |
| public final String stringField; | |
| private Thing(int intField, long longField, double doubleField, String stringField) { | |
| this.intField = intField; | |
| this.longField = longField; | |
| this.doubleField = doubleField; | |
| this.stringField = stringField; | |
| } | |
| public int getIntField() { | |
| return intField; | |
| } | |
| public long getLongField() { | |
| return longField; | |
| } | |
| public double getDoubleField() { | |
| return doubleField; | |
| } | |
| public String getStringField() { | |
| return stringField; | |
| } | |
| } | |
| private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; | |
| private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; | |
| private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; | |
| private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" }; | |
| private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 }; | |
| private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) { | |
| for (int i=0; i<comparisons.length; i++) { | |
| assertEquals(comparisons.length + 1, things.length); | |
| assertEquals(comparisons[i], comp.compare(things[i], things[i+1])); | |
| assertEquals(-comparisons[i], comp.compare(things[i+1], things[i])); | |
| } | |
| } | |
| public void testIntComparator() { | |
| Thing[] things = new Thing[intValues.length]; | |
| for (int i=0; i<intValues.length; i++) | |
| things[i] = new Thing(intValues[i], 0L, 0.0, null); | |
| Comparator<Thing> comp = Comparator.comparingInt(new ToIntFunction<Thing>() { | |
| @Override | |
| public int applyAsInt(Thing thing) { | |
| return thing.getIntField(); | |
| } | |
| }); | |
| assertComparisons(things, comp, comparisons); | |
| } | |
| public void testLongComparator() { | |
| Thing[] things = new Thing[longValues.length]; | |
| for (int i=0; i<longValues.length; i++) | |
| things[i] = new Thing(0, longValues[i], 0.0, null); | |
| Comparator<Thing> comp = Comparator.comparingLong(new ToLongFunction<Thing>() { | |
| @Override | |
| public long applyAsLong(Thing thing) { | |
| return thing.getLongField(); | |
| } | |
| }); | |
| assertComparisons(things, comp, comparisons); | |
| } | |
| public void testDoubleComparator() { | |
| Thing[] things = new Thing[doubleValues.length]; | |
| for (int i=0; i<doubleValues.length; i++) | |
| things[i] = new Thing(0, 0L, doubleValues[i], null); | |
| Comparator<Thing> comp = Comparator.comparingDouble(new ToDoubleFunction<Thing>() { | |
| @Override | |
| public double applyAsDouble(Thing thing) { | |
| return thing.getDoubleField(); | |
| } | |
| }); | |
| assertComparisons(things, comp, comparisons); | |
| } | |
| public void testComparing() { | |
| Thing[] things = new Thing[doubleValues.length]; | |
| for (int i=0; i<doubleValues.length; i++) | |
| things[i] = new Thing(0, 0L, 0.0, stringValues[i]); | |
| Comparator<Thing> comp = Comparator.comparing(new Function<Thing, String>() { | |
| @Override | |
| public String apply(Thing thing) { | |
| return thing.getStringField(); | |
| } | |
| }); | |
| assertComparisons(things, comp, comparisons); | |
| } | |
| public void testNaturalOrderComparator() { | |
| Comparator<String> comp = Comparator.naturalOrder(); | |
| assertComparisons(stringValues, comp, comparisons); | |
| } | |
| public void testReverseComparator() { | |
| Comparator<String> cmpr = Comparator.reverseOrder(); | |
| Comparator<String> cmp = cmpr.reversed(); | |
| assertEquals(cmp.reversed(), cmpr); | |
| assertEquals(0, cmp.compare("a", "a")); | |
| assertEquals(0, cmpr.compare("a", "a")); | |
| assertTrue(cmp.compare("a", "b") < 0); | |
| assertTrue(cmpr.compare("a", "b") > 0); | |
| assertTrue(cmp.compare("b", "a") > 0); | |
| assertTrue(cmpr.compare("b", "a") < 0); | |
| } | |
| public void testReverseComparator2() { | |
| Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length(); | |
| Comparator<String> cmpr = cmp.reversed(); | |
| assertEquals(cmpr.reversed(), cmp); | |
| assertEquals(0, cmp.compare("abc", "def")); | |
| assertEquals(0, cmpr.compare("abc", "def")); | |
| assertTrue(cmp.compare("abcd", "def") > 0); | |
| assertTrue(cmpr.compare("abcd", "def") < 0); | |
| assertTrue(cmp.compare("abc", "defg") < 0); | |
| assertTrue(cmpr.compare("abc", "defg") > 0); | |
| } | |
| private <T> void assertComparison(Comparator<T> cmp, T less, T greater) { | |
| assertTrue(cmp.compare(less, greater) < 0, "less"); | |
| assertTrue(cmp.compare(less, less) == 0, "equal"); | |
| assertTrue(cmp.compare(greater, greater) == 0, "equal"); | |
| assertTrue(cmp.compare(greater, less) > 0, "greater"); | |
| } | |
| private static class People { | |
| final String firstName; | |
| final String lastName; | |
| final int age; | |
| People(String first, String last, int age) { | |
| firstName = first; | |
| lastName = last; | |
| this.age = age; | |
| } | |
| String getFirstName() { return firstName; } | |
| String getLastName() { return lastName; } | |
| int getAge() { return age; } | |
| long getAgeAsLong() { return (long) age; }; | |
| double getAgeAsDouble() { return (double) age; }; | |
| } | |
| private final People people[] = { | |
| new People("John", "Doe", 34), | |
| new People("Mary", "Doe", 30), | |
| new People("Maria", "Doe", 14), | |
| new People("Jonah", "Doe", 10), | |
| new People("John", "Cook", 54), | |
| new People("Mary", "Cook", 50), | |
| new People("Mary", null, 25), | |
| new People("John", null, 27) | |
| }; | |
| public void testComparatorDefaultMethods() { | |
| Comparator<People> cmp = Comparator.comparing(People::getFirstName); | |
| Comparator<People> cmp2 = Comparator.comparing(People::getLastName); | |
| // reverseOrder | |
| assertComparison(cmp.reversed(), people[1], people[0]); | |
| // thenComparing(Comparator) | |
| assertComparison(cmp.thenComparing(cmp2), people[0], people[1]); | |
| assertComparison(cmp.thenComparing(cmp2), people[4], people[0]); | |
| // thenComparing(Function) | |
| assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); | |
| assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); | |
| // thenComparing(ToIntFunction) | |
| assertComparison(cmp.thenComparingInt(People::getAge), people[0], people[1]); | |
| assertComparison(cmp.thenComparingInt(People::getAge), people[1], people[5]); | |
| // thenComparing(ToLongFunction) | |
| assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[0], people[1]); | |
| assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[1], people[5]); | |
| // thenComparing(ToDoubleFunction) | |
| assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[0], people[1]); | |
| assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[1], people[5]); | |
| } | |
| public void testNullsFirst() { | |
| Comparator<String> strcmp = Comparator.nullsFirst(Comparator.naturalOrder()); | |
| Comparator<People> cmp = Comparator.comparing(People::getLastName, strcmp) | |
| .thenComparing(People::getFirstName, strcmp); | |
| // Mary.null vs Mary.Cook - solve by last name | |
| assertComparison(cmp, people[6], people[5]); | |
| // John.null vs Mary.null - solve by first name | |
| assertComparison(cmp, people[7], people[6]); | |
| // More than one thenComparing | |
| strcmp = Comparator.nullsFirst(Comparator.comparingInt(String::length) | |
| .thenComparing(String.CASE_INSENSITIVE_ORDER)); | |
| assertComparison(strcmp, null, "abc"); | |
| assertComparison(strcmp, "ab", "abc"); | |
| assertComparison(strcmp, "abc", "def"); | |
| assertEquals(0, strcmp.compare("abc", "ABC")); | |
| // Ensure reverse still handle null properly | |
| Comparator<String> strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder()); | |
| assertComparison(strcmp2, "abc", null); | |
| assertComparison(strcmp2, "abc", "ab"); | |
| assertComparison(strcmp2, "def", "abc"); | |
| assertComparison(strcmp2, "ABC", "abc"); | |
| // Considering non-null values to be equal | |
| Comparator<String> blind = Comparator.nullsFirst(null); | |
| assertComparison(blind, null, "abc"); | |
| assertEquals(0, blind.compare("abc", "def")); | |
| // reverse still consider non-null values to be equal | |
| strcmp = blind.reversed(); | |
| assertComparison(strcmp, "abc", null); | |
| assertEquals(0, strcmp.compare("abc", "def")); | |
| // chain with another comparator to compare non-nulls | |
| strcmp = blind.thenComparing(Comparator.naturalOrder()); | |
| assertComparison(strcmp, null, "abc"); | |
| assertComparison(strcmp, "abc", "def"); | |
| } | |
| public void testNullsLast() { | |
| Comparator<String> strcmp = Comparator.nullsLast(Comparator.naturalOrder()); | |
| Comparator<People> cmp = Comparator.comparing(People::getLastName, strcmp) | |
| .thenComparing(People::getFirstName, strcmp); | |
| // Mary.null vs Mary.Cook - solve by last name | |
| assertComparison(cmp, people[5], people[6]); | |
| // John.null vs Mary.null - solve by first name | |
| assertComparison(cmp, people[7], people[6]); | |
| // More than one thenComparing | |
| strcmp = Comparator.nullsLast(Comparator.comparingInt(String::length) | |
| .thenComparing(String.CASE_INSENSITIVE_ORDER)); | |
| assertComparison(strcmp, "abc", null); | |
| assertComparison(strcmp, "ab", "abc"); | |
| assertComparison(strcmp, "abc", "def"); | |
| // Ensure reverse still handle null properly | |
| Comparator<String> strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder()); | |
| assertComparison(strcmp2, null, "abc"); | |
| assertComparison(strcmp2, "abc", "ab"); | |
| assertComparison(strcmp2, "def", "abc"); | |
| assertComparison(strcmp2, "ABC", "abc"); | |
| // Considering non-null values to be equal | |
| Comparator<String> blind = Comparator.nullsLast(null); | |
| assertComparison(blind, "abc", null); | |
| assertEquals(0, blind.compare("abc", "def")); | |
| // reverse still consider non-null values to be equal | |
| strcmp = blind.reversed(); | |
| assertComparison(strcmp, null, "abc"); | |
| assertEquals(0, strcmp.compare("abc", "def")); | |
| // chain with another comparator to compare non-nulls | |
| strcmp = blind.thenComparing(Comparator.naturalOrder()); | |
| assertComparison(strcmp, "abc", null); | |
| assertComparison(strcmp, "abc", "def"); | |
| } | |
| public void testComposeComparator() { | |
| // Longer string in front | |
| Comparator<String> first = (s1, s2) -> s2.length() - s1.length(); | |
| Comparator<String> second = Comparator.naturalOrder(); | |
| Comparator<String> composed = first.thenComparing(second); | |
| assertTrue(composed.compare("abcdefg", "abcdef") < 0); | |
| assertTrue(composed.compare("abcdef", "abcdefg") > 0); | |
| assertTrue(composed.compare("abcdef", "abcdef") == 0); | |
| assertTrue(composed.compare("abcdef", "ghijkl") < 0); | |
| assertTrue(composed.compare("ghijkl", "abcdefg") > 0); | |
| } | |
| public void testNulls() { | |
| try { | |
| Comparator.<String>naturalOrder().compare("abc", (String) null); | |
| fail("expected NPE with naturalOrder"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator.<String>naturalOrder().compare((String) null, "abc"); | |
| fail("expected NPE with naturalOrder"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator.<String>reverseOrder().compare("abc", (String) null); | |
| fail("expected NPE with naturalOrder"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator.<String>reverseOrder().compare((String) null, "abc"); | |
| fail("expected NPE with naturalOrder"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparing(null, Comparator.<String>naturalOrder()); | |
| fail("comparing(null, cmp) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparing(People::getFirstName, null); | |
| fail("comparing(f, null) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparing(null); | |
| fail("comparing(null) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparingInt(null); | |
| fail("comparing(null) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparingLong(null); | |
| fail("comparing(null) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| try { | |
| Comparator<People> cmp = Comparator.comparingDouble(null); | |
| fail("comparing(null) should throw NPE"); | |
| } catch (NullPointerException npe) {} | |
| } | |
| public void testNaturalAndReverseIdentity() { | |
| var naturalOrder = Comparator.<String>naturalOrder(); | |
| var reverseOrder = Comparator.<String>reverseOrder(); | |
| assertEquals( | |
| naturalOrder, | |
| Collections.reverseOrder(reverseOrder), | |
| "Comparator.naturalOrder() and Collections.reverseOrder(Comparator.reverseOrder()) not equal"); | |
| assertEquals( | |
| reverseOrder, | |
| Collections.reverseOrder(naturalOrder), | |
| "Comparator.reverseOrder() and Collections.reverseOrder(Comparator.naturalOrder()) not equal"); | |
| assertEquals( | |
| naturalOrder.reversed(), | |
| reverseOrder, | |
| "Comparator.naturalOrder().reversed() amd Comparator.reverseOrder() not equal"); | |
| assertEquals( | |
| reverseOrder.reversed(), | |
| naturalOrder, | |
| "Comparator.reverseOrder().reversed() and Comparator.naturalOrder() not equal"); | |
| } | |
| } |