View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4;
18  
19  import static org.apache.commons.collections4.functors.EqualPredicate.equalPredicate;
20  import static org.junit.jupiter.api.Assertions.assertAll;
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertSame;
26  import static org.junit.jupiter.api.Assertions.assertThrows;
27  import static org.junit.jupiter.api.Assertions.assertTrue;
28  import static org.junit.jupiter.api.Assertions.fail;
29  
30  import java.util.ArrayList;
31  import java.util.Arrays;
32  import java.util.Collection;
33  import java.util.Collections;
34  import java.util.HashSet;
35  import java.util.LinkedList;
36  import java.util.List;
37  import java.util.Set;
38  
39  import org.apache.commons.collections4.bag.HashBag;
40  import org.apache.commons.lang3.StringUtils;
41  import org.junit.jupiter.api.BeforeEach;
42  import org.junit.jupiter.api.Test;
43  
44  /**
45   * Tests for IterableUtils.
46   */
47  public class IterableUtilsTest {
48  
49      private static final Predicate<Number> EQUALS_TWO = input -> input.intValue() == 2;
50  
51      private static final Predicate<Number> EVEN = input -> input.intValue() % 2 == 0;
52  
53      /**
54       * Iterable of {@link Integer}s
55       */
56      private Iterable<Integer> iterableA;
57  
58      /**
59       * Iterable of {@link Long}s
60       */
61      private Iterable<Long> iterableB;
62  
63      /**
64       * An empty Iterable.
65       */
66      private Iterable<Integer> emptyIterable;
67  
68      public void firstFromIterable() throws Exception {
69          // Collection, entry exists
70          final Bag<String> bag = new HashBag<>();
71          bag.add("element", 1);
72          assertEquals("element", IterableUtils.first(bag));
73      }
74  
75      public void getFromIterable() throws Exception {
76          // Collection, entry exists
77          final Bag<String> bag = new HashBag<>();
78          bag.add("element", 1);
79          assertEquals("element", IterableUtils.get(bag, 0));
80      }
81  
82      @BeforeEach
83      public void setUp() {
84          final Collection<Integer> collectionA = new ArrayList<>();
85          collectionA.add(1);
86          collectionA.add(2);
87          collectionA.add(2);
88          collectionA.add(3);
89          collectionA.add(3);
90          collectionA.add(3);
91          collectionA.add(4);
92          collectionA.add(4);
93          collectionA.add(4);
94          collectionA.add(4);
95          iterableA = collectionA;
96  
97          final Collection<Long> collectionB = new LinkedList<>();
98          collectionB.add(5L);
99          collectionB.add(4L);
100         collectionB.add(4L);
101         collectionB.add(3L);
102         collectionB.add(3L);
103         collectionB.add(3L);
104         collectionB.add(2L);
105         collectionB.add(2L);
106         collectionB.add(2L);
107         collectionB.add(2L);
108         iterableB = collectionB;
109 
110         emptyIterable = Collections.emptyList();
111     }
112 
113     @Test
114     public void testContainsWithEquator() {
115         final List<String> base = new ArrayList<>();
116         base.add("AC");
117         base.add("BB");
118         base.add("CA");
119 
120         final Equator<String> secondLetterEquator = new Equator<String>() {
121 
122             @Override
123             public boolean equate(final String o1, final String o2) {
124                 return o1.charAt(1) == o2.charAt(1);
125             }
126 
127             @Override
128             public int hash(final String o) {
129                 return o.charAt(1);
130             }
131 
132         };
133 
134         assertFalse(base.contains("CC"));
135         assertTrue(IterableUtils.contains(base, "AC", secondLetterEquator));
136         assertTrue(IterableUtils.contains(base, "CC", secondLetterEquator));
137         assertFalse(IterableUtils.contains(base, "CX", secondLetterEquator));
138         assertFalse(IterableUtils.contains(null, null, secondLetterEquator));
139 
140         assertThrows(NullPointerException.class, () -> IterableUtils.contains(base, "AC", null),
141                 "expecting NullPointerException");
142     }
143 
144     @Test
145     public void testCountMatches() {
146         assertEquals(4, IterableUtils.countMatches(iterableB, EQUALS_TWO));
147         assertEquals(0, IterableUtils.countMatches(null, EQUALS_TWO));
148         assertAll(
149                 () -> assertThrows(NullPointerException.class, () -> assertEquals(0, IterableUtils.countMatches(iterableA, null)),
150                         "predicate must not be null"),
151                 () -> assertThrows(NullPointerException.class, () -> assertEquals(0, IterableUtils.countMatches(null, null)),
152                         "predicate must not be null")
153         );
154     }
155 
156     @Test
157     public void testFind() {
158         Predicate<Number> testPredicate = equalPredicate(4);
159         Integer test = IterableUtils.find(iterableA, testPredicate);
160         assertEquals(4, (int) test);
161         testPredicate = equalPredicate(45);
162         test = IterableUtils.find(iterableA, testPredicate);
163         assertNull(test);
164         assertNull(IterableUtils.find(null, testPredicate));
165 
166         assertThrows(NullPointerException.class, () -> IterableUtils.find(iterableA, null),
167                 "expecting NullPointerException");
168     }
169 
170     @Test
171     public void testFirstFromIterableIndexOutOfBoundsException() throws Exception {
172         // Collection, entry exists
173         final Bag<String> bag = new HashBag<>();
174         // Collection, non-existent entry
175         assertThrows(IndexOutOfBoundsException.class, () -> IterableUtils.first(bag));
176     }
177 
178     @Test
179     public void testForEach() {
180         final List<Integer> listA = new ArrayList<>();
181         listA.add(1);
182 
183         final List<Integer> listB = new ArrayList<>();
184         listB.add(2);
185 
186         final Closure<List<Integer>> testClosure = ClosureUtils.invokerClosure("clear");
187         final Collection<List<Integer>> col = new ArrayList<>();
188         col.add(listA);
189         col.add(listB);
190         IterableUtils.forEach(col, testClosure);
191         assertTrue(listA.isEmpty() && listB.isEmpty());
192 
193         assertThrows(NullPointerException.class, () -> IterableUtils.forEach(col, null),
194                 "expecting NullPointerException");
195 
196         IterableUtils.forEach(null, testClosure);
197 
198         // null should be OK
199         col.add(null);
200         IterableUtils.forEach(col, testClosure);
201     }
202 
203     @Test
204     public void testForEachButLast() {
205         final List<Integer> listA = new ArrayList<>();
206         listA.add(1);
207 
208         final List<Integer> listB = new ArrayList<>();
209         listB.add(2);
210 
211         final Closure<List<Integer>> testClosure = ClosureUtils.invokerClosure("clear");
212         final Collection<List<Integer>> col = new ArrayList<>();
213         col.add(listA);
214         col.add(listB);
215         List<Integer> last = IterableUtils.forEachButLast(col, testClosure);
216         assertTrue(listA.isEmpty() && !listB.isEmpty());
217         assertSame(listB, last);
218 
219         assertThrows(NullPointerException.class, () -> IterableUtils.forEachButLast(col, null),
220                 "expecting NullPointerException");
221 
222         IterableUtils.forEachButLast(null, testClosure);
223 
224         // null should be OK
225         col.add(null);
226         col.add(null);
227         last = IterableUtils.forEachButLast(col, testClosure);
228         assertNull(last);
229     }
230 
231     @Test
232     public void testForEachFailure() {
233         final Closure<String> testClosure = ClosureUtils.invokerClosure("clear");
234         final Collection<String> col = new ArrayList<>();
235         col.add("x");
236         assertThrows(FunctorException.class, () -> IterableUtils.forEach(col, testClosure));
237     }
238 
239     @Test
240     public void testFrequency() {
241         // null iterable test
242         assertEquals(0, IterableUtils.frequency(null, 1));
243 
244         assertEquals(1, IterableUtils.frequency(iterableA, 1));
245         assertEquals(2, IterableUtils.frequency(iterableA, 2));
246         assertEquals(3, IterableUtils.frequency(iterableA, 3));
247         assertEquals(4, IterableUtils.frequency(iterableA, 4));
248         assertEquals(0, IterableUtils.frequency(iterableA, 5));
249 
250         assertEquals(0, IterableUtils.frequency(iterableB, 1L));
251         assertEquals(4, IterableUtils.frequency(iterableB, 2L));
252         assertEquals(3, IterableUtils.frequency(iterableB, 3L));
253         assertEquals(2, IterableUtils.frequency(iterableB, 4L));
254         assertEquals(1, IterableUtils.frequency(iterableB, 5L));
255 
256         // Ensure that generic bounds accept valid parameters, but return
257         // expected results
258         // e.g. no longs in the "int" Iterable<Number>, and vice versa.
259         final Iterable<Number> iterableIntAsNumber = Arrays.<Number>asList(1, 2, 3, 4, 5);
260         final Iterable<Number> iterableLongAsNumber = Arrays.<Number>asList(1L, 2L, 3L, 4L, 5L);
261         assertEquals(0, IterableUtils.frequency(iterableIntAsNumber, 2L));
262         assertEquals(0, IterableUtils.frequency(iterableLongAsNumber, 2));
263 
264         final Set<String> set = new HashSet<>();
265         set.add("A");
266         set.add("C");
267         set.add("E");
268         set.add("E");
269         assertEquals(1, IterableUtils.frequency(set, "A"));
270         assertEquals(0, IterableUtils.frequency(set, "B"));
271         assertEquals(1, IterableUtils.frequency(set, "C"));
272         assertEquals(0, IterableUtils.frequency(set, "D"));
273         assertEquals(1, IterableUtils.frequency(set, "E"));
274 
275         final Bag<String> bag = new HashBag<>();
276         bag.add("A", 3);
277         bag.add("C");
278         bag.add("E");
279         bag.add("E");
280         assertEquals(3, IterableUtils.frequency(bag, "A"));
281         assertEquals(0, IterableUtils.frequency(bag, "B"));
282         assertEquals(1, IterableUtils.frequency(bag, "C"));
283         assertEquals(0, IterableUtils.frequency(bag, "D"));
284         assertEquals(2, IterableUtils.frequency(bag, "E"));
285     }
286 
287     @Test
288     public void testFrequencyOfNull() {
289         final List<String> list = new ArrayList<>();
290         assertEquals(0, IterableUtils.frequency(list, null));
291         list.add("A");
292         assertEquals(0, IterableUtils.frequency(list, null));
293         list.add(null);
294         assertEquals(1, IterableUtils.frequency(list, null));
295         list.add("B");
296         assertEquals(1, IterableUtils.frequency(list, null));
297         list.add(null);
298         assertEquals(2, IterableUtils.frequency(list, null));
299         list.add("B");
300         assertEquals(2, IterableUtils.frequency(list, null));
301         list.add(null);
302         assertEquals(3, IterableUtils.frequency(list, null));
303     }
304 
305     @Test
306     public void testGetFromIterableIndexOutOfBoundsException() throws Exception {
307         // Collection, entry exists
308         final Bag<String> bag = new HashBag<>();
309         bag.add("element", 1);
310         // Collection, non-existent entry
311         assertThrows(IndexOutOfBoundsException.class, () -> IterableUtils.get(bag, 1));
312     }
313 
314     @Test
315     public void testIndexOf() {
316         Predicate<Number> testPredicate = equalPredicate((Number) 4);
317         int index = IterableUtils.indexOf(iterableA, testPredicate);
318         assertEquals(6, index);
319         testPredicate = equalPredicate((Number) 45);
320         index = IterableUtils.indexOf(iterableA, testPredicate);
321         assertEquals(-1, index);
322         assertEquals(-1, IterableUtils.indexOf(null, testPredicate));
323 
324         assertThrows(NullPointerException.class, () -> IterableUtils.indexOf(iterableA, null),
325                 "expecting NullPointerException");
326     }
327 
328     @Test
329     public void testMatchesAll() {
330         assertThrows(NullPointerException.class, () -> assertFalse(IterableUtils.matchesAll(null, null)),
331                 "predicate must not be null");
332 
333         assertThrows(NullPointerException.class, () -> assertFalse(IterableUtils.matchesAll(iterableA, null)),
334                 "predicate must not be null");
335 
336         final Predicate<Integer> lessThanFive = object -> object < 5;
337         assertTrue(IterableUtils.matchesAll(iterableA, lessThanFive));
338 
339         final Predicate<Integer> lessThanFour = object -> object < 4;
340         assertFalse(IterableUtils.matchesAll(iterableA, lessThanFour));
341 
342         assertTrue(IterableUtils.matchesAll(null, lessThanFour));
343         assertTrue(IterableUtils.matchesAll(emptyIterable, lessThanFour));
344     }
345 
346     @Test
347     public void testMatchesAny() {
348         final List<Integer> list = new ArrayList<>();
349 
350         assertThrows(NullPointerException.class, () -> assertFalse(IterableUtils.matchesAny(null, null)),
351                 "predicate must not be null");
352 
353         assertThrows(NullPointerException.class, () -> assertFalse(IterableUtils.matchesAny(list, null)),
354                 "predicate must not be null");
355 
356         assertFalse(IterableUtils.matchesAny(null, EQUALS_TWO));
357         assertFalse(IterableUtils.matchesAny(list, EQUALS_TWO));
358         list.add(1);
359         list.add(3);
360         list.add(4);
361         assertFalse(IterableUtils.matchesAny(list, EQUALS_TWO));
362 
363         list.add(2);
364         assertTrue(IterableUtils.matchesAny(list, EQUALS_TWO));
365     }
366 
367     @SuppressWarnings("unchecked")
368     @Test
369     public void testPartition() {
370         final List<Integer> input = new ArrayList<>();
371         input.add(1);
372         input.add(2);
373         input.add(3);
374         input.add(4);
375         List<List<Integer>> partitions = IterableUtils.partition(input, EQUALS_TWO);
376         assertEquals(2, partitions.size());
377 
378         // first partition contains 2
379         Collection<Integer> partition = partitions.get(0);
380         assertEquals(1, partition.size());
381         assertEquals(2, CollectionUtils.extractSingleton(partition).intValue());
382 
383         // second partition contains 1, 3, and 4
384         final Integer[] expected = {1, 3, 4};
385         partition = partitions.get(1);
386         assertArrayEquals(expected, partition.toArray());
387 
388         partitions = IterableUtils.partition((List<Integer>) null, EQUALS_TWO);
389         assertEquals(2, partitions.size());
390         assertTrue(partitions.get(0).isEmpty());
391         assertTrue(partitions.get(1).isEmpty());
392 
393         partitions = IterableUtils.partition(input);
394         assertEquals(1, partitions.size());
395         assertEquals(input, partitions.get(0));
396 
397         assertThrows(NullPointerException.class, () -> IterableUtils.partition(input, (Predicate<Integer>) null),
398                 "expecting NullPointerException");
399     }
400 
401     @SuppressWarnings("unchecked")
402     @Test
403     public void testPartitionMultiplePredicates() {
404         final List<Integer> input = new ArrayList<>();
405         input.add(1);
406         input.add(2);
407         input.add(3);
408         input.add(4);
409         final List<List<Integer>> partitions = IterableUtils.partition(input, EQUALS_TWO, EVEN);
410 
411         // first partition contains 2
412         Collection<Integer> partition = partitions.get(0);
413         assertEquals(1, partition.size());
414         assertEquals(2, partition.iterator().next().intValue());
415 
416         // second partition contains 4
417         partition = partitions.get(1);
418         assertEquals(1, partition.size());
419         assertEquals(4, partition.iterator().next().intValue());
420 
421         // third partition contains 1 and 3
422         final Integer[] expected = {1, 3};
423         partition = partitions.get(2);
424         assertArrayEquals(expected, partition.toArray());
425 
426         assertThrows(NullPointerException.class, () -> IterableUtils.partition(input, EQUALS_TWO, null));
427     }
428 
429     @Test
430     public void testSize() {
431         assertEquals(0, IterableUtils.size(null));
432     }
433 
434     @Test
435     public void testToString() {
436         String result = IterableUtils.toString(iterableA);
437         assertEquals("[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]", result);
438 
439         result = IterableUtils.toString(new ArrayList<>());
440         assertEquals("[]", result);
441 
442         result = IterableUtils.toString(null);
443         assertEquals("[]", result);
444 
445         result = IterableUtils.toString(iterableA, input -> Integer.toString(input * 2));
446         assertEquals("[2, 4, 4, 6, 6, 6, 8, 8, 8, 8]", result);
447 
448         result = IterableUtils.toString(new ArrayList<>(), input -> {
449             fail("not supposed to reach here");
450             return StringUtils.EMPTY;
451         });
452         assertEquals("[]", result);
453 
454         result = IterableUtils.toString(null, input -> {
455             fail("not supposed to reach here");
456             return StringUtils.EMPTY;
457         });
458         assertEquals("[]", result);
459     }
460 
461     @Test
462     public void testToStringDelimiter() {
463 
464         final Transformer<Integer, String> transformer = input -> Integer.toString(input * 2);
465 
466         String result = IterableUtils.toString(iterableA, transformer, StringUtils.EMPTY, StringUtils.EMPTY, StringUtils.EMPTY);
467         assertEquals("2446668888", result);
468 
469         result = IterableUtils.toString(iterableA, transformer, ",", StringUtils.EMPTY, StringUtils.EMPTY);
470         assertEquals("2,4,4,6,6,6,8,8,8,8", result);
471 
472         result = IterableUtils.toString(iterableA, transformer, StringUtils.EMPTY, "[", "]");
473         assertEquals("[2446668888]", result);
474 
475         result = IterableUtils.toString(iterableA, transformer, ",", "[", "]");
476         assertEquals("[2,4,4,6,6,6,8,8,8,8]", result);
477 
478         result = IterableUtils.toString(iterableA, transformer, ",", "[[", "]]");
479         assertEquals("[[2,4,4,6,6,6,8,8,8,8]]", result);
480 
481         result = IterableUtils.toString(iterableA, transformer, ",,", "[", "]");
482         assertEquals("[2,,4,,4,,6,,6,,6,,8,,8,,8,,8]", result);
483 
484         result = IterableUtils.toString(iterableA, transformer, ",,", "((", "))");
485         assertEquals("((2,,4,,4,,6,,6,,6,,8,,8,,8,,8))", result);
486 
487         result = IterableUtils.toString(new ArrayList<>(), transformer, StringUtils.EMPTY, "(", ")");
488         assertEquals("()", result);
489 
490         result = IterableUtils.toString(new ArrayList<>(), transformer, StringUtils.EMPTY, StringUtils.EMPTY, StringUtils.EMPTY);
491         assertEquals(StringUtils.EMPTY, result);
492     }
493 
494     @Test
495     public void testToStringWithNullArguments() {
496         final String result = IterableUtils.toString(null, input -> {
497             fail("not supposed to reach here");
498             return StringUtils.EMPTY;
499         }, StringUtils.EMPTY, "(", ")");
500         assertEquals("()", result);
501         assertAll(
502                 () -> assertThrows(NullPointerException.class, () -> IterableUtils.toString(new ArrayList<>(), null, StringUtils.EMPTY, "(", ")"),
503                         "expecting NullPointerException"),
504                 () -> assertThrows(NullPointerException.class, () ->
505                                 IterableUtils.toString(new ArrayList<>(), input -> {
506                                     fail("not supposed to reach here");
507                                     return StringUtils.EMPTY;
508                                 }, null, "(", ")"),
509                         "expecting NullPointerException"),
510                 () -> assertThrows(NullPointerException.class, () -> IterableUtils.toString(new ArrayList<>(), input -> {
511                     fail("not supposed to reach here");
512                     return StringUtils.EMPTY;
513                 }, StringUtils.EMPTY, null, ")"),
514                         "expecting NullPointerException"),
515                 () -> assertThrows(NullPointerException.class, () -> IterableUtils.toString(new ArrayList<>(), input -> {
516                     fail("not supposed to reach here");
517                     return StringUtils.EMPTY;
518                 }, StringUtils.EMPTY, "(", null),
519                         "expecting NullPointerException")
520         );
521     }
522 
523 }