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 } |
|