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