1 /*
   2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8001667
  27  * @run testng BasicTest
  28  */
  29 
  30 import java.util.Comparator;
  31 import java.util.Comparators;
  32 import java.util.AbstractMap;
  33 import java.util.Map;
  34 import org.testng.annotations.Test;
  35 
  36 import java.util.function.Function;
  37 import java.util.function.ToIntFunction;
  38 import java.util.function.ToLongFunction;
  39 import java.util.function.ToDoubleFunction;
  40 
  41 import static org.testng.Assert.assertEquals;
  42 import static org.testng.Assert.assertTrue;
  43 import static org.testng.Assert.assertSame;
  44 
  45 /**
  46  * Unit tests for helper methods in Comparators
  47  */
  48 @Test(groups = "unit")
  49 public class BasicTest {
  50     private static class Thing {
  51         public final int intField;
  52         public final long longField;
  53         public final double doubleField;
  54         public final String stringField;
  55 
  56         private Thing(int intField, long longField, double doubleField, String stringField) {
  57             this.intField = intField;
  58             this.longField = longField;
  59             this.doubleField = doubleField;
  60             this.stringField = stringField;
  61         }
  62 
  63         public int getIntField() {
  64             return intField;
  65         }
  66 
  67         public long getLongField() {
  68             return longField;
  69         }
  70 
  71         public double getDoubleField() {
  72             return doubleField;
  73         }
  74 
  75         public String getStringField() {
  76             return stringField;
  77         }
  78     }
  79 
  80     private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  81     private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  82     private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  83     private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" };
  84     private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 };
  85 
  86     private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) {
  87         for (int i=0; i<comparisons.length; i++) {
  88             assertEquals(comparisons.length + 1, things.length);
  89             assertEquals(comparisons[i], comp.compare(things[i], things[i+1]));
  90             assertEquals(-comparisons[i], comp.compare(things[i+1], things[i]));
  91         }
  92     }
  93 
  94     public void testIntComparator() {
  95         Thing[] things = new Thing[intValues.length];
  96         for (int i=0; i<intValues.length; i++)
  97             things[i] = new Thing(intValues[i], 0L, 0.0, null);
  98         Comparator<Thing> comp = Comparators.comparing(new ToIntFunction<BasicTest.Thing>() {
  99             @Override
 100             public int applyAsInt(Thing thing) {
 101                 return thing.getIntField();
 102             }
 103         });
 104 
 105         assertComparisons(things, comp, comparisons);
 106     }
 107 
 108     public void testLongComparator() {
 109         Thing[] things = new Thing[longValues.length];
 110         for (int i=0; i<longValues.length; i++)
 111             things[i] = new Thing(0, longValues[i], 0.0, null);
 112         Comparator<Thing> comp = Comparators.comparing(new ToLongFunction<BasicTest.Thing>() {
 113             @Override
 114             public long applyAsLong(Thing thing) {
 115                 return thing.getLongField();
 116             }
 117         });
 118 
 119         assertComparisons(things, comp, comparisons);
 120     }
 121 
 122     public void testDoubleComparator() {
 123         Thing[] things = new Thing[doubleValues.length];
 124         for (int i=0; i<doubleValues.length; i++)
 125             things[i] = new Thing(0, 0L, doubleValues[i], null);
 126         Comparator<Thing> comp = Comparators.comparing(new ToDoubleFunction<BasicTest.Thing>() {
 127             @Override
 128             public double applyAsDouble(Thing thing) {
 129                 return thing.getDoubleField();
 130             }
 131         });
 132 
 133         assertComparisons(things, comp, comparisons);
 134     }
 135 
 136     public void testComparing() {
 137         Thing[] things = new Thing[doubleValues.length];
 138         for (int i=0; i<doubleValues.length; i++)
 139             things[i] = new Thing(0, 0L, 0.0, stringValues[i]);
 140         Comparator<Thing> comp = Comparators.comparing(new Function<Thing, String>() {
 141             @Override
 142             public String apply(Thing thing) {
 143                 return thing.getStringField();
 144             }
 145         });
 146 
 147         assertComparisons(things, comp, comparisons);
 148     }
 149 
 150     public void testNaturalOrderComparator() {
 151         Comparator<String> comp = Comparators.naturalOrder();
 152 
 153         assertComparisons(stringValues, comp, comparisons);
 154     }
 155 
 156     public void testReverseComparator() {
 157         Comparator<String> cmpr = Comparators.reverseOrder();
 158         Comparator<String> cmp = cmpr.reverseOrder();
 159 
 160         assertEquals(cmp.reverseOrder(), cmpr);
 161         assertEquals(0, cmp.compare("a", "a"));
 162         assertEquals(0, cmpr.compare("a", "a"));
 163         assertTrue(cmp.compare("a", "b") < 0);
 164         assertTrue(cmpr.compare("a", "b") > 0);
 165         assertTrue(cmp.compare("b", "a") > 0);
 166         assertTrue(cmpr.compare("b", "a") < 0);
 167     }
 168 
 169     public void testReverseComparator2() {
 170         Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length();
 171         Comparator<String> cmpr = cmp.reverseOrder();
 172 
 173         assertEquals(cmpr.reverseOrder(), cmp);
 174         assertEquals(0, cmp.compare("abc", "def"));
 175         assertEquals(0, cmpr.compare("abc", "def"));
 176         assertTrue(cmp.compare("abcd", "def") > 0);
 177         assertTrue(cmpr.compare("abcd", "def") < 0);
 178         assertTrue(cmp.compare("abc", "defg") < 0);
 179         assertTrue(cmpr.compare("abc", "defg") > 0);
 180     }
 181 
 182     @Test(expectedExceptions=NullPointerException.class)
 183     public void testReverseComparatorNPE() {
 184         Comparator<String> cmp = Comparators.reverseOrder(null);
 185     }
 186 
 187     public void testComposeComparator() {
 188         // Longer string in front
 189         Comparator<String> first = (s1, s2) -> s2.length() - s1.length();
 190         Comparator<String> second = Comparators.naturalOrder();
 191         Comparator<String> composed = Comparators.compose(first, second);
 192 
 193         assertTrue(composed.compare("abcdefg", "abcdef") < 0);
 194         assertTrue(composed.compare("abcdef", "abcdefg") > 0);
 195         assertTrue(composed.compare("abcdef", "abcdef") == 0);
 196         assertTrue(composed.compare("abcdef", "ghijkl") < 0);
 197         assertTrue(composed.compare("ghijkl", "abcdefg") > 0);
 198     }
 199 
 200     private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2,
 201                                         Comparator<Map.Entry<K, V>> ck,
 202                                         Comparator<Map.Entry<K, V>> cv) {
 203         final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1);
 204         final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2);
 205         final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1);
 206         final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2);
 207 
 208         assertTrue(ck.compare(p11, p11) == 0);
 209         assertTrue(ck.compare(p12, p11) == 0);
 210         assertTrue(ck.compare(p11, p12) == 0);
 211         assertTrue(ck.compare(p12, p22) < 0);
 212         assertTrue(ck.compare(p12, p21) < 0);
 213         assertTrue(ck.compare(p21, p11) > 0);
 214         assertTrue(ck.compare(p21, p12) > 0);
 215 
 216         assertTrue(cv.compare(p11, p11) == 0);
 217         assertTrue(cv.compare(p12, p11) > 0);
 218         assertTrue(cv.compare(p11, p12) < 0);
 219         assertTrue(cv.compare(p12, p22) == 0);
 220         assertTrue(cv.compare(p12, p21) > 0);
 221         assertTrue(cv.compare(p21, p11) == 0);
 222         assertTrue(cv.compare(p21, p12) < 0);
 223 
 224         Comparator<Map.Entry<K, V>> cmp = Comparators.compose(ck, cv);
 225         assertTrue(cmp.compare(p11, p11) == 0);
 226         assertTrue(cmp.compare(p12, p11) > 0);
 227         assertTrue(cmp.compare(p11, p12) < 0);
 228         assertTrue(cmp.compare(p12, p22) < 0);
 229         assertTrue(cmp.compare(p12, p21) < 0);
 230         assertTrue(cmp.compare(p21, p11) > 0);
 231         assertTrue(cmp.compare(p21, p12) > 0);
 232 
 233         cmp = Comparators.compose(cv, ck);
 234         assertTrue(cmp.compare(p11, p11) == 0);
 235         assertTrue(cmp.compare(p12, p11) > 0);
 236         assertTrue(cmp.compare(p11, p12) < 0);
 237         assertTrue(cmp.compare(p12, p22) < 0);
 238         assertTrue(cmp.compare(p12, p21) > 0);
 239         assertTrue(cmp.compare(p21, p11) > 0);
 240         assertTrue(cmp.compare(p21, p12) < 0);
 241     }
 242 
 243     public void testKVComparatorable() {
 244         assertPairComparison(1, "ABC", 2, "XYZ",
 245                          Comparators.<Integer, String>naturalOrderKeys(),
 246                          Comparators.<Integer, String>naturalOrderValues());
 247     }
 248 
 249     private static class People {
 250         final String firstName;
 251         final String lastName;
 252         final int age;
 253 
 254         People(String first, String last, int age) {
 255             firstName = first;
 256             lastName = last;
 257             this.age = age;
 258         }
 259 
 260         String getFirstName() { return firstName; }
 261         String getLastName() { return lastName; }
 262         int getAge() { return age; }
 263         long getAgeAsLong() { return (long) age; };
 264         double getAgeAsDouble() { return (double) age; };
 265     }
 266 
 267     private final People people[] = {
 268         new People("John", "Doe", 34),
 269         new People("Mary", "Doe", 30),
 270         new People("Maria", "Doe", 14),
 271         new People("Jonah", "Doe", 10),
 272         new People("John", "Cook", 54),
 273         new People("Mary", "Cook", 50),
 274     };
 275 
 276     public void testKVComparators() {
 277         // Comparator<People> cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable
 278         // We can use simple comparator, but those have been tested above.
 279         // Thus choose to do compose for some level of interation.
 280         Comparator<People> cmp1 = Comparators.comparing((Function<People, String>) People::getFirstName);
 281         Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName);
 282         Comparator<People> cmp = Comparators.compose(cmp1, cmp2);
 283 
 284         assertPairComparison(people[0], people[0], people[1], people[1],
 285                          Comparators.<People, People>byKey(cmp),
 286                          Comparators.<People, People>byValue(cmp));
 287 
 288     }
 289 
 290     private <T> void assertComparison(Comparator<T> cmp, T less, T greater) {
 291         assertTrue(cmp.compare(less, greater) < 0, "less");
 292         assertTrue(cmp.compare(less, less) == 0, "equal");
 293         assertTrue(cmp.compare(greater, less) > 0, "greater");
 294     }
 295 
 296     public void testComparatorDefaultMethods() {
 297         Comparator<People> cmp = Comparators.comparing((Function<People, String>) People::getFirstName);
 298         Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName);
 299         // reverseOrder
 300         assertComparison(cmp.reverseOrder(), people[1], people[0]);
 301         // thenComparing(Comparator)
 302         assertComparison(cmp.thenComparing(cmp2), people[0], people[1]);
 303         assertComparison(cmp.thenComparing(cmp2), people[4], people[0]);
 304         // thenComparing(Function)
 305         assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]);
 306         assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]);
 307         // thenComparing(ToIntFunction)
 308         assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]);
 309         assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]);
 310         // thenComparing(ToLongFunction)
 311         assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]);
 312         assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]);
 313         // thenComparing(ToDoubleFunction)
 314         assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]);
 315         assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]);
 316     }
 317 
 318     public void testGreaterOf() {
 319         // lesser
 320         assertSame(Comparators.greaterOf(Comparators.comparing(
 321                                     (Function<People, String>) People::getFirstName))
 322                               .apply(people[0], people[1]),
 323                    people[1]);
 324         // euqal
 325         assertSame(Comparators.greaterOf(Comparators.comparing(
 326                                     (Function<People, String>) People::getLastName))
 327                               .apply(people[0], people[1]),
 328                    people[0]);
 329         // greater
 330         assertSame(Comparators.greaterOf(Comparators.comparing(
 331                                     (ToIntFunction<People>) People::getAge))
 332                               .apply(people[0], people[1]),
 333                    people[0]);
 334     }
 335 
 336     public void testLesserOf() {
 337         // lesser
 338         assertSame(Comparators.lesserOf(Comparators.comparing(
 339                                     (Function<People, String>) People::getFirstName))
 340                               .apply(people[0], people[1]),
 341                    people[0]);
 342         // euqal
 343         assertSame(Comparators.lesserOf(Comparators.comparing(
 344                                     (Function<People, String>) People::getLastName))
 345                               .apply(people[0], people[1]),
 346                    people[0]);
 347         // greater
 348         assertSame(Comparators.lesserOf(Comparators.comparing(
 349                                     (ToIntFunction<People>) People::getAge))
 350                               .apply(people[0], people[1]),
 351                    people[1]);
 352     }
 353 }