/* * Copyright (c) 2012, 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 8001667 * @run testng ComparatorsTest */ import java.util.Comparator; import java.util.Comparators; import java.util.AbstractMap; import java.util.Map; import org.testng.annotations.Test; import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; import java.util.function.ToDoubleFunction; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertSame; /** * Unit tests for helper methods in Comparators */ @Test(groups = "unit") public class ComparatorsTest { 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 void assertComparisons(T[] things, Comparator comp, int[] comparisons) { for (int i=0; i comp = Comparators.comparing(new ToIntFunction() { @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 comp = Comparators.comparing(new ToLongFunction() { @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 comp = Comparators.comparing(new ToDoubleFunction() { @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 comp = Comparators.comparing(new Function() { @Override public String apply(Thing thing) { return thing.getStringField(); } }); assertComparisons(things, comp, comparisons); } public void testNaturalOrderComparator() { Comparator comp = Comparators.naturalOrder(); assertComparisons(stringValues, comp, comparisons); } public void testReverseComparator() { Comparator cmpr = Comparators.reverseOrder(); Comparator cmp = cmpr.reverseOrder(); assertEquals(cmp.reverseOrder(), 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 cmp = (s1, s2) -> s1.length() - s2.length(); Comparator cmpr = cmp.reverseOrder(); assertEquals(cmpr.reverseOrder(), 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); } @Test(expectedExceptions=NullPointerException.class) public void testReverseComparatorNPE() { Comparator cmp = Comparators.reverseOrder(null); } public void testComposeComparator() { // Longer string in front Comparator first = (s1, s2) -> s2.length() - s1.length(); Comparator second = Comparators.naturalOrder(); Comparator composed = Comparators.compose(first, 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); } private void assertPairComparison(K k1, V v1, K k2, V v2, Comparator> ck, Comparator> cv) { final Map.Entry p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1); final Map.Entry p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2); final Map.Entry p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1); final Map.Entry p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2); assertTrue(ck.compare(p11, p11) == 0); assertTrue(ck.compare(p12, p11) == 0); assertTrue(ck.compare(p11, p12) == 0); assertTrue(ck.compare(p12, p22) < 0); assertTrue(ck.compare(p12, p21) < 0); assertTrue(ck.compare(p21, p11) > 0); assertTrue(ck.compare(p21, p12) > 0); assertTrue(cv.compare(p11, p11) == 0); assertTrue(cv.compare(p12, p11) > 0); assertTrue(cv.compare(p11, p12) < 0); assertTrue(cv.compare(p12, p22) == 0); assertTrue(cv.compare(p12, p21) > 0); assertTrue(cv.compare(p21, p11) == 0); assertTrue(cv.compare(p21, p12) < 0); Comparator> cmp = Comparators.compose(ck, cv); assertTrue(cmp.compare(p11, p11) == 0); assertTrue(cmp.compare(p12, p11) > 0); assertTrue(cmp.compare(p11, p12) < 0); assertTrue(cmp.compare(p12, p22) < 0); assertTrue(cmp.compare(p12, p21) < 0); assertTrue(cmp.compare(p21, p11) > 0); assertTrue(cmp.compare(p21, p12) > 0); cmp = Comparators.compose(cv, ck); assertTrue(cmp.compare(p11, p11) == 0); assertTrue(cmp.compare(p12, p11) > 0); assertTrue(cmp.compare(p11, p12) < 0); assertTrue(cmp.compare(p12, p22) < 0); assertTrue(cmp.compare(p12, p21) > 0); assertTrue(cmp.compare(p21, p11) > 0); assertTrue(cmp.compare(p21, p12) < 0); } public void testKVComparatorable() { assertPairComparison(1, "ABC", 2, "XYZ", Comparators.naturalOrderKeys(), Comparators.naturalOrderValues()); } 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), }; public void testKVComparators() { // Comparator cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable // We can use simple comparator, but those have been tested above. // Thus choose to do compose for some level of interation. Comparator cmp1 = Comparators.comparing((Function) People::getFirstName); Comparator cmp2 = Comparators.comparing((Function) People::getLastName); Comparator cmp = Comparators.compose(cmp1, cmp2); assertPairComparison(people[0], people[0], people[1], people[1], Comparators.byKey(cmp), Comparators.byValue(cmp)); } private void assertComparison(Comparator cmp, T less, T greater) { assertTrue(cmp.compare(less, greater) < 0, "less"); assertTrue(cmp.compare(less, less) == 0, "equal"); assertTrue(cmp.compare(greater, less) > 0, "greater"); } public void testComparatorDefaultMethods() { Comparator cmp = Comparators.comparing((Function) People::getFirstName); Comparator cmp2 = Comparators.comparing((Function) People::getLastName); // reverseOrder assertComparison(cmp.reverseOrder(), 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.thenComparing(People::getAge), people[0], people[1]); assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); // thenComparing(ToLongFunction) assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); // thenComparing(ToDoubleFunction) assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); } public void testGreaterOf() { // lesser assertSame(Comparators.greaterOf(Comparators.comparing( (Function) People::getFirstName)) .apply(people[0], people[1]), people[1]); // euqal assertSame(Comparators.greaterOf(Comparators.comparing( (Function) People::getLastName)) .apply(people[0], people[1]), people[0]); // greater assertSame(Comparators.greaterOf(Comparators.comparing( (ToIntFunction) People::getAge)) .apply(people[0], people[1]), people[0]); } public void testLesserOf() { // lesser assertSame(Comparators.lesserOf(Comparators.comparing( (Function) People::getFirstName)) .apply(people[0], people[1]), people[0]); // euqal assertSame(Comparators.lesserOf(Comparators.comparing( (Function) People::getLastName)) .apply(people[0], people[1]), people[0]); // greater assertSame(Comparators.lesserOf(Comparators.comparing( (ToIntFunction) People::getAge)) .apply(people[0], people[1]), people[1]); } }