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