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.comparing(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.comparing(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.comparing(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((Function<People, String>) People::getFirstName); 215 Comparator<People> cmp2 = Comparator.comparing((Function<People, String>) 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.thenComparing(People::getAge), people[0], people[1]); 226 assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); 227 // thenComparing(ToLongFunction) 228 assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); 229 assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); 230 // thenComparing(ToDoubleFunction) 231 assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); 232 assertComparison(cmp.thenComparing(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.<People, String>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.comparing((ToIntFunction<String>) 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.<People, String>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.comparing((ToIntFunction<String>) 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((Function<People, String>) null, Comparator.<String>naturalOrder()); 345 fail("comparing(null, cmp) should throw NPE"); 346 } catch (NullPointerException npe) {} 347 try { 348 Comparator<People> cmp = Comparator.comparing((Function<People, String>) People::getFirstName, null); 349 fail("comparing(f, null) should throw NPE"); 350 } catch (NullPointerException npe) {} 351 352 try { 353 Comparator<People> cmp = Comparator.comparing((Function<People, String>) null); 354 fail("comparing(null) should throw NPE"); 355 } catch (NullPointerException npe) {} 356 try { 357 Comparator<People> cmp = Comparator.comparing((ToIntFunction<People>) null); 358 fail("comparing(null) should throw NPE"); 359 } catch (NullPointerException npe) {} 360 try { 361 Comparator<People> cmp = Comparator.comparing((ToLongFunction<People>) null); 362 fail("comparing(null) should throw NPE"); 363 } catch (NullPointerException npe) {} 364 try { 365 Comparator<People> cmp = Comparator.comparing((ToDoubleFunction<People>) null); 366 fail("comparing(null) should throw NPE"); 367 } catch (NullPointerException npe) {} 368 } 369 }