• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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