1 /*
   2  * Copyright (c) 2013, 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  * @summary Comparator default method tests
  27  * @run testng BasicTest
  28  */
  29 
  30 import java.util.TreeMap;
  31 import java.util.Comparator;
  32 import org.testng.annotations.Test;
  33 
  34 import java.util.function.Function;
  35 import java.util.function.ToIntFunction;
  36 import java.util.function.ToLongFunction;
  37 import java.util.function.ToDoubleFunction;
  38 
  39 import static org.testng.Assert.assertEquals;
  40 import static org.testng.Assert.assertTrue;
  41 import static org.testng.Assert.fail;
  42 
  43 @Test(groups = "unit")
  44 public class BasicTest {
  45     private static class Thing {
  46         public final int intField;
  47         public final long longField;
  48         public final double doubleField;
  49         public final String stringField;
  50 
  51         private Thing(int intField, long longField, double doubleField, String stringField) {
  52             this.intField = intField;
  53             this.longField = longField;
  54             this.doubleField = doubleField;
  55             this.stringField = stringField;
  56         }
  57 
  58         public int getIntField() {
  59             return intField;
  60         }
  61 
  62         public long getLongField() {
  63             return longField;
  64         }
  65 
  66         public double getDoubleField() {
  67             return doubleField;
  68         }
  69 
  70         public String getStringField() {
  71             return stringField;
  72         }
  73     }
  74 
  75     private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  76     private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  77     private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 };
  78     private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" };
  79     private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 };
  80 
  81     private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) {
  82         for (int i=0; i<comparisons.length; i++) {
  83             assertEquals(comparisons.length + 1, things.length);
  84             assertEquals(comparisons[i], comp.compare(things[i], things[i+1]));
  85             assertEquals(-comparisons[i], comp.compare(things[i+1], things[i]));
  86         }
  87     }
  88 
  89     public void testIntComparator() {
  90         Thing[] things = new Thing[intValues.length];
  91         for (int i=0; i<intValues.length; i++)
  92             things[i] = new Thing(intValues[i], 0L, 0.0, null);
  93         Comparator<Thing> comp = Comparator.comparingInt(new ToIntFunction<Thing>() {
  94             @Override
  95             public int applyAsInt(Thing thing) {
  96                 return thing.getIntField();
  97             }
  98         });
  99 
 100         assertComparisons(things, comp, comparisons);
 101     }
 102 
 103     public void testLongComparator() {
 104         Thing[] things = new Thing[longValues.length];
 105         for (int i=0; i<longValues.length; i++)
 106             things[i] = new Thing(0, longValues[i], 0.0, null);
 107         Comparator<Thing> comp = Comparator.comparingLong(new ToLongFunction<Thing>() {
 108             @Override
 109             public long applyAsLong(Thing thing) {
 110                 return thing.getLongField();
 111             }
 112         });
 113 
 114         assertComparisons(things, comp, comparisons);
 115     }
 116 
 117     public void testDoubleComparator() {
 118         Thing[] things = new Thing[doubleValues.length];
 119         for (int i=0; i<doubleValues.length; i++)
 120             things[i] = new Thing(0, 0L, doubleValues[i], null);
 121         Comparator<Thing> comp = Comparator.comparingDouble(new ToDoubleFunction<Thing>() {
 122             @Override
 123             public double applyAsDouble(Thing thing) {
 124                 return thing.getDoubleField();
 125             }
 126         });
 127 
 128         assertComparisons(things, comp, comparisons);
 129     }
 130 
 131     public void testComparing() {
 132         Thing[] things = new Thing[doubleValues.length];
 133         for (int i=0; i<doubleValues.length; i++)
 134             things[i] = new Thing(0, 0L, 0.0, stringValues[i]);
 135         Comparator<Thing> comp = Comparator.comparing(new Function<Thing, String>() {
 136             @Override
 137             public String apply(Thing thing) {
 138                 return thing.getStringField();
 139             }
 140         });
 141 
 142         assertComparisons(things, comp, comparisons);
 143     }
 144 
 145     public void testNaturalOrderComparator() {
 146         Comparator<String> comp = Comparator.naturalOrder();
 147 
 148         assertComparisons(stringValues, comp, comparisons);
 149     }
 150 
 151     public void testReverseComparator() {
 152         Comparator<String> cmpr = Comparator.reverseOrder();
 153         Comparator<String> cmp = cmpr.reversed();
 154 
 155         assertEquals(cmp.reversed(), cmpr);
 156         assertEquals(0, cmp.compare("a", "a"));
 157         assertEquals(0, cmpr.compare("a", "a"));
 158         assertTrue(cmp.compare("a", "b") < 0);
 159         assertTrue(cmpr.compare("a", "b") > 0);
 160         assertTrue(cmp.compare("b", "a") > 0);
 161         assertTrue(cmpr.compare("b", "a") < 0);
 162     }
 163 
 164     public void testReverseComparator2() {
 165         Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length();
 166         Comparator<String> cmpr = cmp.reversed();
 167 
 168         assertEquals(cmpr.reversed(), cmp);
 169         assertEquals(0, cmp.compare("abc", "def"));
 170         assertEquals(0, cmpr.compare("abc", "def"));
 171         assertTrue(cmp.compare("abcd", "def") > 0);
 172         assertTrue(cmpr.compare("abcd", "def") < 0);
 173         assertTrue(cmp.compare("abc", "defg") < 0);
 174         assertTrue(cmpr.compare("abc", "defg") > 0);
 175     }
 176 
 177     private <T> void assertComparison(Comparator<T> cmp, T less, T greater) {
 178         assertTrue(cmp.compare(less, greater) < 0, "less");
 179         assertTrue(cmp.compare(less, less) == 0, "equal");
 180         assertTrue(cmp.compare(greater, greater) == 0, "equal");
 181         assertTrue(cmp.compare(greater, less) > 0, "greater");
 182     }
 183 
 184     private static class People {
 185         final String firstName;
 186         final String lastName;
 187         final int age;
 188 
 189         People(String first, String last, int age) {
 190             firstName = first;
 191             lastName = last;
 192             this.age = age;
 193         }
 194 
 195         String getFirstName() { return firstName; }
 196         String getLastName() { return lastName; }
 197         int getAge() { return age; }
 198         long getAgeAsLong() { return (long) age; };
 199         double getAgeAsDouble() { return (double) age; };
 200     }
 201 
 202     private final People people[] = {
 203         new People("John", "Doe", 34),
 204         new People("Mary", "Doe", 30),
 205         new People("Maria", "Doe", 14),
 206         new People("Jonah", "Doe", 10),
 207         new People("John", "Cook", 54),
 208         new People("Mary", "Cook", 50),
 209         new People("Mary", null, 25),
 210         new People("John", null, 27)
 211     };
 212 
 213     public void testComparatorDefaultMethods() {
 214         Comparator<People> cmp = Comparator.comparing(People::getFirstName);
 215         Comparator<People> cmp2 = Comparator.comparing(People::getLastName);
 216         // reverseOrder
 217         assertComparison(cmp.reversed(), people[1], people[0]);
 218         // thenComparing(Comparator)
 219         assertComparison(cmp.thenComparing(cmp2), people[0], people[1]);
 220         assertComparison(cmp.thenComparing(cmp2), people[4], people[0]);
 221         // thenComparing(Function)
 222         assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]);
 223         assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]);
 224         // thenComparing(ToIntFunction)
 225         assertComparison(cmp.thenComparingInt(People::getAge), people[0], people[1]);
 226         assertComparison(cmp.thenComparingInt(People::getAge), people[1], people[5]);
 227         // thenComparing(ToLongFunction)
 228         assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[0], people[1]);
 229         assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[1], people[5]);
 230         // thenComparing(ToDoubleFunction)
 231         assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[0], people[1]);
 232         assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[1], people[5]);
 233     }
 234 
 235 
 236     public void testNullsFirst() {
 237         Comparator<String> strcmp = Comparator.nullsFirst(Comparator.naturalOrder());
 238         Comparator<People> cmp = Comparator.comparing(People::getLastName, strcmp)
 239                                            .thenComparing(People::getFirstName, strcmp);
 240         // Mary.null vs Mary.Cook - solve by last name
 241         assertComparison(cmp, people[6], people[5]);
 242         // John.null vs Mary.null - solve by first name
 243         assertComparison(cmp, people[7], people[6]);
 244 
 245         // More than one thenComparing
 246         strcmp = Comparator.nullsFirst(Comparator.comparingInt(String::length)
 247                                                  .thenComparing(String.CASE_INSENSITIVE_ORDER));
 248         assertComparison(strcmp, null, "abc");
 249         assertComparison(strcmp, "ab", "abc");
 250         assertComparison(strcmp, "abc", "def");
 251         assertEquals(0, strcmp.compare("abc", "ABC"));
 252 
 253         // Ensure reverse still handle null properly
 254         Comparator<String> strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder());
 255         assertComparison(strcmp2, "abc", null);
 256         assertComparison(strcmp2, "abc", "ab");
 257         assertComparison(strcmp2, "def", "abc");
 258         assertComparison(strcmp2, "ABC", "abc");
 259 
 260         // Considering non-null values to be equal
 261         Comparator<String> blind = Comparator.nullsFirst(null);
 262         assertComparison(blind, null, "abc");
 263         assertEquals(0, blind.compare("abc", "def"));
 264         // reverse still consider non-null values to be equal
 265         strcmp = blind.reversed();
 266         assertComparison(strcmp, "abc", null);
 267         assertEquals(0, strcmp.compare("abc", "def"));
 268         // chain with another comparator to compare non-nulls
 269         strcmp = blind.thenComparing(Comparator.naturalOrder());
 270         assertComparison(strcmp, null, "abc");
 271         assertComparison(strcmp, "abc", "def");
 272     }
 273 
 274     public void testNullsLast() {
 275         Comparator<String> strcmp = Comparator.nullsLast(Comparator.naturalOrder());
 276         Comparator<People> cmp = Comparator.comparing(People::getLastName, strcmp)
 277                                            .thenComparing(People::getFirstName, strcmp);
 278         // Mary.null vs Mary.Cook - solve by last name
 279         assertComparison(cmp, people[5], people[6]);
 280         // John.null vs Mary.null - solve by first name
 281         assertComparison(cmp, people[7], people[6]);
 282 
 283         // More than one thenComparing
 284         strcmp = Comparator.nullsLast(Comparator.comparingInt(String::length)
 285                                                 .thenComparing(String.CASE_INSENSITIVE_ORDER));
 286         assertComparison(strcmp, "abc", null);
 287         assertComparison(strcmp, "ab", "abc");
 288         assertComparison(strcmp, "abc", "def");
 289 
 290         // Ensure reverse still handle null properly
 291         Comparator<String> strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder());
 292         assertComparison(strcmp2, null, "abc");
 293         assertComparison(strcmp2, "abc", "ab");
 294         assertComparison(strcmp2, "def", "abc");
 295         assertComparison(strcmp2, "ABC", "abc");
 296 
 297         // Considering non-null values to be equal
 298         Comparator<String> blind = Comparator.nullsLast(null);
 299         assertComparison(blind, "abc", null);
 300         assertEquals(0, blind.compare("abc", "def"));
 301         // reverse still consider non-null values to be equal
 302         strcmp = blind.reversed();
 303         assertComparison(strcmp, null, "abc");
 304         assertEquals(0, strcmp.compare("abc", "def"));
 305         // chain with another comparator to compare non-nulls
 306         strcmp = blind.thenComparing(Comparator.naturalOrder());
 307         assertComparison(strcmp, "abc", null);
 308         assertComparison(strcmp, "abc", "def");
 309     }
 310 
 311     public void testComposeComparator() {
 312         // Longer string in front
 313         Comparator<String> first = (s1, s2) -> s2.length() - s1.length();
 314         Comparator<String> second = Comparator.naturalOrder();
 315         Comparator<String> composed = first.thenComparing(second);
 316 
 317         assertTrue(composed.compare("abcdefg", "abcdef") < 0);
 318         assertTrue(composed.compare("abcdef", "abcdefg") > 0);
 319         assertTrue(composed.compare("abcdef", "abcdef") == 0);
 320         assertTrue(composed.compare("abcdef", "ghijkl") < 0);
 321         assertTrue(composed.compare("ghijkl", "abcdefg") > 0);
 322     }
 323 
 324     public void testNulls() {
 325         try {
 326             Comparator.<String>naturalOrder().compare("abc", (String) null);
 327             fail("expected NPE with naturalOrder");
 328         } catch (NullPointerException npe) {}
 329         try {
 330             Comparator.<String>naturalOrder().compare((String) null, "abc");
 331             fail("expected NPE with naturalOrder");
 332         } catch (NullPointerException npe) {}
 333 
 334         try {
 335             Comparator.<String>reverseOrder().compare("abc", (String) null);
 336             fail("expected NPE with naturalOrder");
 337         } catch (NullPointerException npe) {}
 338         try {
 339             Comparator.<String>reverseOrder().compare((String) null, "abc");
 340             fail("expected NPE with naturalOrder");
 341         } catch (NullPointerException npe) {}
 342 
 343         try {
 344             Comparator<People> cmp = Comparator.comparing(null, Comparator.<String>naturalOrder());
 345             fail("comparing(null, cmp) should throw NPE");
 346         } catch (NullPointerException npe) {}
 347         try {
 348             Comparator<People> cmp = Comparator.comparing(People::getFirstName, null);
 349             fail("comparing(f, null) should throw NPE");
 350         } catch (NullPointerException npe) {}
 351 
 352         try {
 353             Comparator<People> cmp = Comparator.comparing(null);
 354             fail("comparing(null) should throw NPE");
 355         } catch (NullPointerException npe) {}
 356         try {
 357             Comparator<People> cmp = Comparator.comparingInt(null);
 358             fail("comparing(null) should throw NPE");
 359         } catch (NullPointerException npe) {}
 360         try {
 361             Comparator<People> cmp = Comparator.comparingLong(null);
 362             fail("comparing(null) should throw NPE");
 363         } catch (NullPointerException npe) {}
 364         try {
 365             Comparator<People> cmp = Comparator.comparingDouble(null);
 366             fail("comparing(null) should throw NPE");
 367         } catch (NullPointerException npe) {}
 368     }
 369 }