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    *      https://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.lang3.stream;
18  
19  import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  import static org.junit.jupiter.api.DynamicTest.dynamicTest;
28  
29  import java.lang.reflect.UndeclaredThrowableException;
30  import java.util.ArrayList;
31  import java.util.Arrays;
32  import java.util.Hashtable;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.stream.Collectors;
36  import java.util.stream.Stream;
37  
38  import org.apache.commons.lang3.AbstractLangTest;
39  import org.apache.commons.lang3.function.Failable;
40  import org.apache.commons.lang3.function.FailableConsumer;
41  import org.apache.commons.lang3.function.FailablePredicate;
42  import org.apache.commons.lang3.stream.Streams.FailableStream;
43  import org.junit.jupiter.api.DynamicTest;
44  import org.junit.jupiter.api.Test;
45  import org.junit.jupiter.api.TestFactory;
46  import org.junit.jupiter.api.function.Executable;
47  import org.xml.sax.SAXException;
48  
49  /**
50   * Tests {@link Streams}.
51   */
52  class StreamsTest extends AbstractLangTest {
53  
54      protected <T extends Throwable> FailableConsumer<String, T> asIntConsumer(final T throwable) {
55          return s -> {
56              final int i = Integer.parseInt(s);
57              if (i == 4) {
58                  throw throwable;
59              }
60          };
61      }
62  
63      protected <T extends Throwable> FailablePredicate<Integer, T> asIntPredicate(final T throwable) {
64          return i -> {
65              if (i.intValue() == 5 && throwable != null) {
66                  throw throwable;
67              }
68              return i % 2 == 0;
69          };
70      }
71  
72      private void assertEvenNumbers(final List<Integer> output) {
73          assertEquals(3, output.size());
74          for (int i = 0; i < 3; i++) {
75              assertEquals((i + 1) * 2, output.get(i).intValue());
76          }
77      }
78  
79      @TestFactory
80      public Stream<DynamicTest> simpleStreamFilterFailing() {
81          final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
82          final List<Integer> output = Failable.stream(input).map(Integer::valueOf).filter(asIntPredicate(null)).collect(Collectors.toList());
83          assertEvenNumbers(output);
84          return Stream.of(
85              dynamicTest("IllegalArgumentException", () -> {
86                  final IllegalArgumentException iae = new IllegalArgumentException("Invalid argument: " + 5);
87                  final Executable testMethod = () -> Failable.stream(input).map(Integer::valueOf).filter(asIntPredicate(iae)).collect(Collectors.toList());
88                  final IllegalArgumentException thrown = assertIllegalArgumentException(testMethod);
89                  assertEquals("Invalid argument: " + 5, thrown.getMessage());
90              }),
91              dynamicTest("OutOfMemoryError", () -> {
92                  final OutOfMemoryError oome = new OutOfMemoryError();
93                  final Executable testMethod = () -> Failable.stream(input).map(Integer::valueOf).filter(asIntPredicate(oome)).collect(Collectors.toList());
94                  final OutOfMemoryError thrown = assertThrows(OutOfMemoryError.class, testMethod);
95                  assertNull(thrown.getMessage());
96              }),
97              dynamicTest("SAXException", () -> {
98                  final SAXException se = new SAXException();
99                  final Executable testMethod = () -> Failable.stream(input).map(Integer::valueOf).filter(asIntPredicate(se)).collect(Collectors.toList());
100                 final UndeclaredThrowableException thrown = assertThrows(UndeclaredThrowableException.class, testMethod);
101                 assertNull(thrown.getMessage());
102                 assertEquals(se, thrown.getCause());
103             }));
104     }
105 
106     @TestFactory
107     public Stream<DynamicTest> simpleStreamForEachFailing() {
108         final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
109         return Stream.of(
110             dynamicTest("IllegalArgumentException", () -> {
111                 final IllegalArgumentException ise = new IllegalArgumentException();
112                 final Executable testMethod = () -> Failable.stream(input).forEach(asIntConsumer(ise));
113                 final IllegalArgumentException thrown = assertIllegalArgumentException(testMethod);
114                 assertNull(thrown.getMessage());
115             }),
116             dynamicTest("OutOfMemoryError", () -> {
117                 final OutOfMemoryError oome = new OutOfMemoryError();
118                 final Executable oomeTestMethod = () -> Failable.stream(input).forEach(asIntConsumer(oome));
119                 final OutOfMemoryError oomeThrown = assertThrows(OutOfMemoryError.class, oomeTestMethod);
120                 assertNull(oomeThrown.getMessage());
121             }),
122             dynamicTest("SAXException", () -> {
123                 final SAXException se = new SAXException();
124                 final Executable seTestMethod = () -> Failable.stream(input).forEach(asIntConsumer(se));
125                 final UndeclaredThrowableException seThrown = assertThrows(UndeclaredThrowableException.class, seTestMethod);
126                 assertNull(seThrown.getMessage());
127                 assertEquals(se, seThrown.getCause());
128             }));
129     }
130 
131     @Test
132     void testArrayCollectorCombiner() {
133         final String[] expected = { "A1", "B1" };
134         assertArrayEquals(expected, Stream.of("A", "B").collect(Collectors.mapping(s -> s + "1", Streams.toArray(String.class))));
135         assertArrayEquals(expected, Streams.failableStream("A", "B").collect(Collectors.mapping(s -> s + "1", Streams.toArray(String.class))));
136         final List<String> left = new ArrayList<>();
137         left.add("a");
138         assertEquals(Arrays.asList("a", "b", "c"), Streams.toArray(String.class).combiner().apply(left, Arrays.asList("b", "c")));
139     }
140 
141     @Test
142     void testAssertNotTerminated() {
143         final FailableStream<String> stream = Streams.failableStream("A", "B");
144         assertTrue(stream.allMatch(s -> s.length() == 1));
145         assertThrows(IllegalStateException.class, () -> stream.allMatch(null));
146     }
147 
148     @SuppressWarnings("deprecation")
149     @Test
150     void testDeprefcatedCopnstructor() {
151         assertNotNull(new Streams().toString());
152     }
153 
154     @Test
155     void testFailableAllMatch() {
156         assertTrue(Streams.failableStream("A", "B").allMatch(s -> s.length() == 1));
157         assertFalse(Streams.failableStream("A", "B").allMatch(s -> s.length() == 2));
158     }
159 
160     @Test
161     void testFailableAnyMatch() {
162         assertTrue(Streams.failableStream("A", "B").anyMatch(s -> s.length() == 1));
163         assertTrue(Streams.failableStream("A", "BC").anyMatch(s -> s.length() == 1));
164         assertFalse(Streams.failableStream("A", "B").anyMatch(s -> s.length() == 2));
165     }
166 
167     @Test
168     void testFailableCollect() {
169         assertEquals(Arrays.asList("A", "B"), Streams.failableStream("A", "B").collect(ArrayList::new, ArrayList::add, ArrayList::addAll));
170     }
171 
172     @Test
173     void testFailableReduce() {
174         assertEquals(3, Streams.failableStream(1, 2).reduce(0, (a, b) -> a + b));
175     }
176 
177     @Test
178     void testFailableStream() {
179         assertEquals(1, Streams.failableStream(1).collect(Collectors.toList()).size());
180         assertEquals(0, Streams.failableStream(Stream.empty()).collect(Collectors.toList()).size());
181     }
182 
183     @Test
184     void testInstanceOfStream() {
185         assertEquals(2, Streams.instancesOf(String.class, Arrays.asList("A", "B")).collect(Collectors.toList()).size());
186         assertEquals(2, Streams.instancesOf(String.class, Arrays.asList(null, "A", null, "B", null)).collect(Collectors.toList()).size());
187         assertEquals(0, Streams.instancesOf(String.class, Arrays.asList(null, null)).collect(Collectors.toList()).size());
188         //
189         final List<Object> objects = Arrays.asList("A", "B");
190         assertEquals(2, Streams.instancesOf(String.class, objects).collect(Collectors.toList()).size());
191     }
192 
193     @Test
194     void testNonNull() {
195         assertEquals(0, Streams.nonNull().collect(Collectors.toList()).size());
196         assertEquals(0, Streams.nonNull((Stream<?>) null).collect(Collectors.toList()).size());
197         assertEquals(1, Streams.nonNull("A").collect(Collectors.toList()).size());
198         assertEquals(1, Streams.nonNull("A", null).collect(Collectors.toList()).size());
199         assertEquals(1, Streams.nonNull(null, "A").collect(Collectors.toList()).size());
200     }
201 
202     @Test
203     void testNullSafeStreamNotNull() {
204         assertEquals(2, Streams.nonNull(Arrays.asList("A", "B")).collect(Collectors.toList()).size());
205         assertEquals(2, Streams.nonNull(Arrays.asList(null, "A", null, "B", null)).collect(Collectors.toList()).size());
206         assertEquals(0, Streams.nonNull(Arrays.asList(null, null)).collect(Collectors.toList()).size());
207     }
208 
209     @Test
210     void testNullSafeStreamNull() {
211         final List<String> input = null;
212         assertEquals(0, Streams.nonNull(input).collect(Collectors.toList()).size());
213     }
214 
215     @Test
216     void testOfArray() {
217         assertEquals(0, Streams.of((Object[]) null).count());
218         assertEquals(1, Streams.of("foo").count());
219         assertEquals(2, Streams.of("foo", "bar").count());
220     }
221 
222     @Test
223     void testOfCollectionNotNull() {
224         assertEquals(2, Streams.of(Arrays.asList("A", "B")).collect(Collectors.toList()).size());
225     }
226 
227     @Test
228     void testOfCollectionNull() {
229         final List<String> input = null;
230         assertEquals(0, Streams.of(input).collect(Collectors.toList()).size());
231     }
232 
233     @Test
234     void testOfEnumeration() {
235         final Hashtable<String, Integer> table = new Hashtable<>();
236         assertEquals(0, Streams.of(table.elements()).count());
237         table.put("One", 1);
238         assertEquals(1, Streams.of(table.elements()).count());
239         table.put("Two", 2);
240         assertEquals(2, Streams.of(table.elements()).count());
241         final List<String> collect = Streams.of(table.keys()).collect(Collectors.toList());
242         assertTrue(collect.contains("One"));
243         assertTrue(collect.contains("Two"));
244         assertEquals(2, collect.size());
245         assertFalse(Streams.of(table.keys()).filter(String::isEmpty).findFirst().isPresent());
246         assertEquals(Arrays.asList("OneOne", "TwoTwo"), Streams.of(table.keys()).map(s -> s + s).collect(Collectors.toList()));
247         assertFalse(Streams.of(new Hashtable<String, Object>().keys()).filter(String::isEmpty).findFirst().isPresent());
248     }
249 
250     @Test
251     void testOfIterableNotNull() {
252         assertEquals(2, Streams.of((Iterable<String>) Arrays.asList("A", "B")).collect(Collectors.toList()).size());
253     }
254 
255     @Test
256     void testOfIterableNull() {
257         final Iterable<String> input = null;
258         assertEquals(0, Streams.of(input).collect(Collectors.toList()).size());
259     }
260 
261     @Test
262     void testOfIteratorNotNull() {
263         assertEquals(2, Streams.of(Arrays.asList("A", "B").iterator()).collect(Collectors.toList()).size());
264     }
265 
266     @Test
267     void testOfIteratorNull() {
268         final Iterator<String> input = null;
269         assertEquals(0, Streams.of(input).collect(Collectors.toList()).size());
270     }
271 
272     @Test
273     void testOfVarArg() {
274         assertEquals(1, Streams.of(1).collect(Collectors.toList()).size());
275         assertEquals(2, Streams.of(1, 2).collect(Collectors.toList()).size());
276     }
277 
278     @Test
279     void testSimpleStreamFilter() {
280         final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
281         final List<Integer> output = Failable.stream(input).map(Integer::valueOf).filter(i -> i.intValue() % 2 == 0).collect(Collectors.toList());
282         assertEvenNumbers(output);
283     }
284 
285     @Test
286     void testSimpleStreamForEach() {
287         final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
288         final List<Integer> output = new ArrayList<>();
289         Failable.stream(input).forEach(s -> output.add(Integer.valueOf(s)));
290         assertEquals(6, output.size());
291         for (int i = 0; i < 6; i++) {
292             assertEquals(i + 1, output.get(i).intValue());
293         }
294     }
295 
296     @Test
297     void testSimpleStreamMap() {
298         final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
299         final List<Integer> output = Failable.stream(input).map(Integer::valueOf).collect(Collectors.toList());
300         assertEquals(6, output.size());
301         for (int i = 0; i < 6; i++) {
302             assertEquals(i + 1, output.get(i).intValue());
303         }
304     }
305 
306     @Test
307     void testSimpleStreamMapFailing() {
308         final List<String> input = Arrays.asList("1", "2", "3", "4 ", "5", "6");
309         final Executable testMethod = () -> Failable.stream(input).map(Integer::valueOf).collect(Collectors.toList());
310         final NumberFormatException thrown = assertThrows(NumberFormatException.class, testMethod);
311         assertEquals("For input string: \"4 \"", thrown.getMessage());
312     }
313 
314     @SuppressWarnings("deprecation")
315     @Test
316     void testStream() {
317         assertEquals(0, Streams.stream(Stream.empty()).collect(Collectors.toList()).size());
318         assertEquals(1, Streams.stream(Stream.of("")).collect(Collectors.toList()).size());
319     }
320 
321     @Test
322     void testStreamCollection() {
323         final List<String> input = Arrays.asList("1", "2", "3", "4", "5", "6");
324         assertEquals(6, Streams.stream(input).collect(Collectors.toList()).size());
325     }
326 
327     @Test
328     void testStreamCollectionNull() {
329         final List<String> input = null;
330         assertEquals(0, Streams.stream(input).collect(Collectors.toList()).size());
331     }
332 
333     @Test
334     void testToArray() {
335         final String[] array = Arrays.asList("2", "3", "1").stream().collect(Streams.toArray(String.class));
336         assertNotNull(array);
337         assertEquals(3, array.length);
338         assertEquals("2", array[0]);
339         assertEquals("3", array[1]);
340         assertEquals("1", array[2]);
341     }
342 
343 }