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 8010279 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.BinaryOperator; 37 import java.util.function.Function; 38 import java.util.function.ToIntFunction; 39 import java.util.function.ToLongFunction; 40 import java.util.function.ToDoubleFunction; 41 42 import static org.testng.Assert.assertEquals; 43 import static org.testng.Assert.assertTrue; 44 import static org.testng.Assert.assertSame; 45 import static org.testng.Assert.fail; 46 47 /** 48 * Unit tests for helper methods in Comparators 49 */ 50 @Test(groups = "unit") 51 public class BasicTest { 52 private static class Thing { 53 public final int intField; 54 public final long longField; 55 public final double doubleField; 56 public final String stringField; 57 58 private Thing(int intField, long longField, double doubleField, String stringField) { 59 this.intField = intField; 60 this.longField = longField; 61 this.doubleField = doubleField; 62 this.stringField = stringField; 63 } 64 65 public int getIntField() { 66 return intField; 67 } 68 69 public long getLongField() { 70 return longField; 71 } 72 73 public double getDoubleField() { 74 return doubleField; 75 } 76 77 public String getStringField() { 78 return stringField; 79 } 80 } 81 82 private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; 83 private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; 84 private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; 85 private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" }; 86 private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 }; 87 88 private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) { 89 for (int i=0; i<comparisons.length; i++) { 90 assertEquals(comparisons.length + 1, things.length); 91 assertEquals(comparisons[i], comp.compare(things[i], things[i+1])); 92 assertEquals(-comparisons[i], comp.compare(things[i+1], things[i])); 93 } 94 } 95 96 public void testIntComparator() { 97 Thing[] things = new Thing[intValues.length]; 98 for (int i=0; i<intValues.length; i++) 99 things[i] = new Thing(intValues[i], 0L, 0.0, null); 100 Comparator<Thing> comp = Comparators.comparing(new ToIntFunction<BasicTest.Thing>() { 101 @Override 102 public int applyAsInt(Thing thing) { 103 return thing.getIntField(); 104 } 105 }); 106 107 assertComparisons(things, comp, comparisons); 108 } 109 110 public void testLongComparator() { 111 Thing[] things = new Thing[longValues.length]; 112 for (int i=0; i<longValues.length; i++) 113 things[i] = new Thing(0, longValues[i], 0.0, null); 114 Comparator<Thing> comp = Comparators.comparing(new ToLongFunction<BasicTest.Thing>() { 115 @Override 116 public long applyAsLong(Thing thing) { 117 return thing.getLongField(); 118 } 119 }); 120 121 assertComparisons(things, comp, comparisons); 122 } 123 124 public void testDoubleComparator() { 125 Thing[] things = new Thing[doubleValues.length]; 126 for (int i=0; i<doubleValues.length; i++) 127 things[i] = new Thing(0, 0L, doubleValues[i], null); 128 Comparator<Thing> comp = Comparators.comparing(new ToDoubleFunction<BasicTest.Thing>() { 129 @Override 130 public double applyAsDouble(Thing thing) { 131 return thing.getDoubleField(); 132 } 133 }); 134 135 assertComparisons(things, comp, comparisons); 136 } 137 138 public void testComparing() { 139 Thing[] things = new Thing[doubleValues.length]; 140 for (int i=0; i<doubleValues.length; i++) 141 things[i] = new Thing(0, 0L, 0.0, stringValues[i]); 142 Comparator<Thing> comp = Comparators.comparing(new Function<Thing, String>() { 143 @Override 144 public String apply(Thing thing) { 145 return thing.getStringField(); 146 } 147 }); 148 149 assertComparisons(things, comp, comparisons); 150 } 151 152 public void testNaturalOrderComparator() { 153 Comparator<String> comp = Comparators.naturalOrder(); 154 155 assertComparisons(stringValues, comp, comparisons); 156 } 157 158 public void testReverseComparator() { 159 Comparator<String> cmpr = Comparators.reverseOrder(); 160 Comparator<String> cmp = cmpr.reverseOrder(); 161 162 assertEquals(cmp.reverseOrder(), cmpr); 163 assertEquals(0, cmp.compare("a", "a")); 164 assertEquals(0, cmpr.compare("a", "a")); 165 assertTrue(cmp.compare("a", "b") < 0); 166 assertTrue(cmpr.compare("a", "b") > 0); 167 assertTrue(cmp.compare("b", "a") > 0); 168 assertTrue(cmpr.compare("b", "a") < 0); 169 } 170 171 public void testReverseComparator2() { 172 Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length(); 173 Comparator<String> cmpr = cmp.reverseOrder(); 174 175 assertEquals(cmpr.reverseOrder(), cmp); 176 assertEquals(0, cmp.compare("abc", "def")); 177 assertEquals(0, cmpr.compare("abc", "def")); 178 assertTrue(cmp.compare("abcd", "def") > 0); 179 assertTrue(cmpr.compare("abcd", "def") < 0); 180 assertTrue(cmp.compare("abc", "defg") < 0); 181 assertTrue(cmpr.compare("abc", "defg") > 0); 182 } 183 184 @Test(expectedExceptions=NullPointerException.class) 185 public void testReverseComparatorNPE() { 186 Comparator<String> cmp = Comparators.reverseOrder(null); 187 } 188 189 public void testComposeComparator() { 190 // Longer string in front 191 Comparator<String> first = (s1, s2) -> s2.length() - s1.length(); 192 Comparator<String> second = Comparators.naturalOrder(); 193 Comparator<String> composed = Comparators.compose(first, second); 194 195 assertTrue(composed.compare("abcdefg", "abcdef") < 0); 196 assertTrue(composed.compare("abcdef", "abcdefg") > 0); 197 assertTrue(composed.compare("abcdef", "abcdef") == 0); 198 assertTrue(composed.compare("abcdef", "ghijkl") < 0); 199 assertTrue(composed.compare("ghijkl", "abcdefg") > 0); 200 } 201 202 private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2, 203 Comparator<Map.Entry<K, V>> ck, 204 Comparator<Map.Entry<K, V>> cv) { 205 final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1); 206 final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2); 207 final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1); 208 final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2); 209 210 assertTrue(ck.compare(p11, p11) == 0); 211 assertTrue(ck.compare(p12, p11) == 0); 212 assertTrue(ck.compare(p11, p12) == 0); 213 assertTrue(ck.compare(p12, p22) < 0); 214 assertTrue(ck.compare(p12, p21) < 0); 215 assertTrue(ck.compare(p21, p11) > 0); 216 assertTrue(ck.compare(p21, p12) > 0); 217 218 assertTrue(cv.compare(p11, p11) == 0); 219 assertTrue(cv.compare(p12, p11) > 0); 220 assertTrue(cv.compare(p11, p12) < 0); 221 assertTrue(cv.compare(p12, p22) == 0); 222 assertTrue(cv.compare(p12, p21) > 0); 223 assertTrue(cv.compare(p21, p11) == 0); 224 assertTrue(cv.compare(p21, p12) < 0); 225 226 Comparator<Map.Entry<K, V>> cmp = Comparators.compose(ck, cv); 227 assertTrue(cmp.compare(p11, p11) == 0); 228 assertTrue(cmp.compare(p12, p11) > 0); 229 assertTrue(cmp.compare(p11, p12) < 0); 230 assertTrue(cmp.compare(p12, p22) < 0); 231 assertTrue(cmp.compare(p12, p21) < 0); 232 assertTrue(cmp.compare(p21, p11) > 0); 233 assertTrue(cmp.compare(p21, p12) > 0); 234 235 cmp = Comparators.compose(cv, ck); 236 assertTrue(cmp.compare(p11, p11) == 0); 237 assertTrue(cmp.compare(p12, p11) > 0); 238 assertTrue(cmp.compare(p11, p12) < 0); 239 assertTrue(cmp.compare(p12, p22) < 0); 240 assertTrue(cmp.compare(p12, p21) > 0); 241 assertTrue(cmp.compare(p21, p11) > 0); 242 assertTrue(cmp.compare(p21, p12) < 0); 243 } 244 245 public void testKVComparatorable() { 246 assertPairComparison(1, "ABC", 2, "XYZ", 247 Comparators.<Integer, String>naturalOrderKeys(), 248 Comparators.<Integer, String>naturalOrderValues()); 249 } 250 251 private static class People { 252 final String firstName; 253 final String lastName; 254 final int age; 255 256 People(String first, String last, int age) { 257 firstName = first; 258 lastName = last; 259 this.age = age; 260 } 261 262 String getFirstName() { return firstName; } 263 String getLastName() { return lastName; } 264 int getAge() { return age; } 265 long getAgeAsLong() { return (long) age; }; 266 double getAgeAsDouble() { return (double) age; }; 267 } 268 269 private final People people[] = { 270 new People("John", "Doe", 34), 271 new People("Mary", "Doe", 30), 272 new People("Maria", "Doe", 14), 273 new People("Jonah", "Doe", 10), 274 new People("John", "Cook", 54), 275 new People("Mary", "Cook", 50), 276 }; 277 278 public void testKVComparators() { 279 // Comparator<People> cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable 280 // We can use simple comparator, but those have been tested above. 281 // Thus choose to do compose for some level of interation. 282 Comparator<People> cmp1 = Comparators.comparing((Function<People, String>) People::getFirstName); 283 Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); 284 Comparator<People> cmp = Comparators.compose(cmp1, cmp2); 285 286 assertPairComparison(people[0], people[0], people[1], people[1], 287 Comparators.<People, People>byKey(cmp), 288 Comparators.<People, People>byValue(cmp)); 289 290 } 291 292 private <T> void assertComparison(Comparator<T> cmp, T less, T greater) { 293 assertTrue(cmp.compare(less, greater) < 0, "less"); 294 assertTrue(cmp.compare(less, less) == 0, "equal"); 295 assertTrue(cmp.compare(greater, less) > 0, "greater"); 296 } 297 298 public void testComparatorDefaultMethods() { 299 Comparator<People> cmp = Comparators.comparing((Function<People, String>) People::getFirstName); 300 Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); 301 // reverseOrder 302 assertComparison(cmp.reverseOrder(), people[1], people[0]); 303 // thenComparing(Comparator) 304 assertComparison(cmp.thenComparing(cmp2), people[0], people[1]); 305 assertComparison(cmp.thenComparing(cmp2), people[4], people[0]); 306 // thenComparing(Function) 307 assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); 308 assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); 309 // thenComparing(ToIntFunction) 310 assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); 311 assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); 312 // thenComparing(ToLongFunction) 313 assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); 314 assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); 315 // thenComparing(ToDoubleFunction) 316 assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); 317 assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); 318 } 319 320 public void testGreaterOf() { 321 // lesser 322 assertSame(Comparators.greaterOf(Comparators.comparing( 323 (Function<People, String>) People::getFirstName)) 324 .apply(people[0], people[1]), 325 people[1]); 326 // euqal 327 assertSame(Comparators.greaterOf(Comparators.comparing( 328 (Function<People, String>) People::getLastName)) 329 .apply(people[0], people[1]), 330 people[0]); 331 // greater 332 assertSame(Comparators.greaterOf(Comparators.comparing( 333 (ToIntFunction<People>) People::getAge)) 334 .apply(people[0], people[1]), 335 people[0]); 336 } 337 338 public void testLesserOf() { 339 // lesser 340 assertSame(Comparators.lesserOf(Comparators.comparing( 341 (Function<People, String>) People::getFirstName)) 342 .apply(people[0], people[1]), 343 people[0]); 344 // euqal 345 assertSame(Comparators.lesserOf(Comparators.comparing( 346 (Function<People, String>) People::getLastName)) 347 .apply(people[0], people[1]), 348 people[0]); 349 // greater 350 assertSame(Comparators.lesserOf(Comparators.comparing( 351 (ToIntFunction<People>) People::getAge)) 352 .apply(people[0], people[1]), 353 people[1]); 354 } 355 356 public void testNulls() { 357 try { 358 Comparators.<String>naturalOrder().compare("abc", (String) null); 359 fail("expected NPE with naturalOrder"); 360 } catch (NullPointerException npe) {} 361 try { 362 Comparators.<String>naturalOrder().compare((String) null, "abc"); 363 fail("expected NPE with naturalOrder"); 364 } catch (NullPointerException npe) {} 365 366 try { 367 Comparators.<String>reverseOrder().compare("abc", (String) null); 368 fail("expected NPE with naturalOrder"); 369 } catch (NullPointerException npe) {} 370 try { 371 Comparators.<String>reverseOrder().compare((String) null, "abc"); 372 fail("expected NPE with naturalOrder"); 373 } catch (NullPointerException npe) {} 374 375 try { 376 Comparator<Map.Entry<String, String>> cmp = Comparators.byKey(null); 377 fail("byKey(null) should throw NPE"); 378 } catch (NullPointerException npe) {} 379 380 try { 381 Comparator<Map.Entry<String, String>> cmp = Comparators.byValue(null); 382 fail("byValue(null) should throw NPE"); 383 } catch (NullPointerException npe) {} 384 385 try { 386 Comparator<People> cmp = Comparators.comparing((Function<People, String>) null); 387 fail("comparing(null) should throw NPE"); 388 } catch (NullPointerException npe) {} 389 try { 390 Comparator<People> cmp = Comparators.comparing((ToIntFunction<People>) null); 391 fail("comparing(null) should throw NPE"); 392 } catch (NullPointerException npe) {} 393 try { 394 Comparator<People> cmp = Comparators.comparing((ToLongFunction<People>) null); 395 fail("comparing(null) should throw NPE"); 396 } catch (NullPointerException npe) {} 397 try { 398 Comparator<People> cmp = Comparators.comparing((ToDoubleFunction<People>) null); 399 fail("comparing(null) should throw NPE"); 400 } catch (NullPointerException npe) {} 401 402 try { 403 BinaryOperator<String> op = Comparators.lesserOf(null); 404 fail("lesserOf(null) should throw NPE"); 405 } catch (NullPointerException npe) {} 406 407 try { 408 BinaryOperator<String> op = Comparators.greaterOf(null); 409 fail("lesserOf(null) should throw NPE"); 410 } catch (NullPointerException npe) {} 411 } 412 }