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