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.lang3;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.io.IOException;
27  import java.io.UncheckedIOException;
28  import java.lang.reflect.UndeclaredThrowableException;
29  import java.util.concurrent.Callable;
30  import java.util.function.BiConsumer;
31  import java.util.function.BiFunction;
32  import java.util.function.BiPredicate;
33  import java.util.function.Consumer;
34  import java.util.function.Function;
35  import java.util.function.Predicate;
36  import java.util.function.Supplier;
37  
38  import org.apache.commons.lang3.Functions.FailableBiConsumer;
39  import org.apache.commons.lang3.Functions.FailableBiFunction;
40  import org.apache.commons.lang3.Functions.FailableCallable;
41  import org.apache.commons.lang3.Functions.FailableConsumer;
42  import org.apache.commons.lang3.Functions.FailableFunction;
43  import org.apache.commons.lang3.Functions.FailableSupplier;
44  import org.junit.jupiter.api.DisplayName;
45  import org.junit.jupiter.api.Test;
46  
47  public class FunctionsTest extends AbstractLangTest {
48  
49      public static class CloseableObject {
50          private boolean closed;
51  
52          public void close() {
53              closed = true;
54          }
55  
56          public boolean isClosed() {
57              return closed;
58          }
59  
60          public void reset() {
61              closed = false;
62          }
63  
64          public void run(final Throwable pTh) throws Throwable {
65              if (pTh != null) {
66                  throw pTh;
67              }
68          }
69      }
70  
71      public static class FailureOnOddInvocations {
72          private static int invocations;
73  
74          static boolean failingBool() throws SomeException {
75              throwOnOdd();
76              return true;
77          }
78  
79          static boolean testDouble(final double value) throws SomeException {
80              throwOnOdd();
81              return true;
82          }
83  
84          static boolean testInt(final int value) throws SomeException {
85              throwOnOdd();
86              return true;
87          }
88  
89          static boolean testLong(final long value) throws SomeException {
90              throwOnOdd();
91              return true;
92          }
93  
94          private static void throwOnOdd() throws SomeException {
95              final int i = ++invocations;
96              if (i % 2 == 1) {
97                  throw new SomeException("Odd Invocation: " + i);
98              }
99          }
100 
101         FailureOnOddInvocations() throws SomeException {
102             throwOnOdd();
103         }
104 
105         boolean getAsBoolean() throws SomeException {
106             throwOnOdd();
107             return true;
108         }
109     }
110 
111     public static class SomeException extends Exception {
112 
113         private static final long serialVersionUID = -4965704778119283411L;
114 
115         private Throwable t;
116 
117         SomeException(final String message) {
118             super(message);
119         }
120 
121         public void setThrowable(final Throwable throwable) {
122             t = throwable;
123         }
124 
125         public void test() throws Throwable {
126             if (t != null) {
127                 throw t;
128             }
129         }
130     }
131 
132     public static class Testable<T, P> {
133         private T acceptedObject;
134         private P acceptedPrimitiveObject1;
135         private P acceptedPrimitiveObject2;
136         private Throwable throwable;
137 
138         Testable(final Throwable throwable) {
139             this.throwable = throwable;
140         }
141 
142         public T getAcceptedObject() {
143             return acceptedObject;
144         }
145 
146         public P getAcceptedPrimitiveObject1() {
147             return acceptedPrimitiveObject1;
148         }
149 
150         public P getAcceptedPrimitiveObject2() {
151             return acceptedPrimitiveObject2;
152         }
153 
154         public void setThrowable(final Throwable throwable) {
155             this.throwable = throwable;
156         }
157 
158         public void test() throws Throwable {
159             test(throwable);
160         }
161 
162         public Object test(final Object input1, final Object input2) throws Throwable {
163             test(throwable);
164             return acceptedObject;
165         }
166 
167         public void test(final Throwable throwable) throws Throwable {
168             if (throwable != null) {
169                 throw throwable;
170             }
171         }
172 
173         public boolean testAsBooleanPrimitive() throws Throwable {
174             return testAsBooleanPrimitive(throwable);
175         }
176 
177         public boolean testAsBooleanPrimitive(final Throwable throwable) throws Throwable {
178             if (throwable != null) {
179                 throw throwable;
180             }
181             return false;
182         }
183 
184         public double testAsDoublePrimitive() throws Throwable {
185             return testAsDoublePrimitive(throwable);
186         }
187 
188         public double testAsDoublePrimitive(final Throwable throwable) throws Throwable {
189             if (throwable != null) {
190                 throw throwable;
191             }
192             return 0;
193         }
194 
195         public Integer testAsInteger() throws Throwable {
196             return testAsInteger(throwable);
197         }
198 
199         public Integer testAsInteger(final Throwable throwable) throws Throwable {
200             if (throwable != null) {
201                 throw throwable;
202             }
203             return 0;
204         }
205 
206         public int testAsIntPrimitive() throws Throwable {
207             return testAsIntPrimitive(throwable);
208         }
209 
210         public int testAsIntPrimitive(final Throwable throwable) throws Throwable {
211             if (throwable != null) {
212                 throw throwable;
213             }
214             return 0;
215         }
216 
217         public long testAsLongPrimitive() throws Throwable {
218             return testAsLongPrimitive(throwable);
219         }
220 
221         public long testAsLongPrimitive(final Throwable throwable) throws Throwable {
222             if (throwable != null) {
223                 throw throwable;
224             }
225             return 0;
226         }
227 
228         public void testDouble(final double i) throws Throwable {
229             test(throwable);
230             acceptedPrimitiveObject1 = (P) ((Double) i);
231         }
232 
233         public double testDoubleDouble(final double i, final double j) throws Throwable {
234             test(throwable);
235             acceptedPrimitiveObject1 = (P) ((Double) i);
236             acceptedPrimitiveObject2 = (P) ((Double) j);
237             return 3d;
238         }
239 
240         public void testInt(final int i) throws Throwable {
241             test(throwable);
242             acceptedPrimitiveObject1 = (P) ((Integer) i);
243         }
244 
245         public void testLong(final long i) throws Throwable {
246             test(throwable);
247             acceptedPrimitiveObject1 = (P) ((Long) i);
248         }
249 
250         public void testObjDouble(final T object, final double i) throws Throwable {
251             test(throwable);
252             acceptedObject = object;
253             acceptedPrimitiveObject1 = (P) ((Double) i);
254         }
255 
256         public void testObjInt(final T object, final int i) throws Throwable {
257             test(throwable);
258             acceptedObject = object;
259             acceptedPrimitiveObject1 = (P) ((Integer) i);
260         }
261 
262         public void testObjLong(final T object, final long i) throws Throwable {
263             test(throwable);
264             acceptedObject = object;
265             acceptedPrimitiveObject1 = (P) ((Long) i);
266         }
267     }
268 
269     @Test
270     public void testAcceptBiConsumer() {
271         final IllegalStateException ise = new IllegalStateException();
272         final Testable<?, ?> testable = new Testable<>(null);
273         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(Testable::test, testable, ise));
274         assertSame(ise, e);
275 
276         final Error error = new OutOfMemoryError();
277         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(Testable::test, testable, error));
278         assertSame(error, e);
279 
280         final IOException ioe = new IOException("Unknown I/O error");
281         testable.setThrowable(ioe);
282         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(Testable::test, testable, ioe));
283         final Throwable t = e.getCause();
284         assertNotNull(t);
285         assertSame(ioe, t);
286 
287         testable.setThrowable(null);
288         Functions.accept(Testable::test, testable, (Throwable) null);
289     }
290 
291     @Test
292     public void testAcceptConsumer() {
293         final IllegalStateException ise = new IllegalStateException();
294         final Testable<?, ?> testable = new Testable<>(ise);
295         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(Testable::test, testable));
296         assertSame(ise, e);
297 
298         final Error error = new OutOfMemoryError();
299         testable.setThrowable(error);
300         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(Testable::test, testable));
301         assertSame(error, e);
302 
303         final IOException ioe = new IOException("Unknown I/O error");
304         testable.setThrowable(ioe);
305         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(Testable::test, testable));
306         final Throwable t = e.getCause();
307         assertNotNull(t);
308         assertSame(ioe, t);
309 
310         testable.setThrowable(null);
311         Functions.accept(Testable::test, testable);
312     }
313 
314     @Test
315     public void testAcceptDoubleConsumer() {
316         final IllegalStateException ise = new IllegalStateException();
317         final Testable<?, Double> testable = new Testable<>(ise);
318         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testDouble, 1d));
319         assertSame(ise, e);
320         assertNull(testable.getAcceptedPrimitiveObject1());
321 
322         final Error error = new OutOfMemoryError();
323         testable.setThrowable(error);
324         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testDouble, 1d));
325         assertSame(error, e);
326         assertNull(testable.getAcceptedPrimitiveObject1());
327 
328         final IOException ioe = new IOException("Unknown I/O error");
329         testable.setThrowable(ioe);
330         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testDouble, 1d));
331         final Throwable t = e.getCause();
332         assertNotNull(t);
333         assertSame(ioe, t);
334         assertNull(testable.getAcceptedPrimitiveObject1());
335 
336         testable.setThrowable(null);
337         Functions.accept(testable::testDouble, 1d);
338         assertEquals(1, testable.getAcceptedPrimitiveObject1());
339     }
340 
341     @Test
342     public void testAcceptIntConsumer() {
343         final IllegalStateException ise = new IllegalStateException();
344         final Testable<?, Integer> testable = new Testable<>(ise);
345         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testInt, 1));
346         assertSame(ise, e);
347         assertNull(testable.getAcceptedPrimitiveObject1());
348 
349         final Error error = new OutOfMemoryError();
350         testable.setThrowable(error);
351         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testInt, 1));
352         assertSame(error, e);
353         assertNull(testable.getAcceptedPrimitiveObject1());
354 
355         final IOException ioe = new IOException("Unknown I/O error");
356         testable.setThrowable(ioe);
357         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testInt, 1));
358         final Throwable t = e.getCause();
359         assertNotNull(t);
360         assertSame(ioe, t);
361         assertNull(testable.getAcceptedPrimitiveObject1());
362 
363         testable.setThrowable(null);
364         Functions.accept(testable::testInt, 1);
365         assertEquals(1, testable.getAcceptedPrimitiveObject1());
366     }
367 
368     @Test
369     public void testAcceptLongConsumer() {
370         final IllegalStateException ise = new IllegalStateException();
371         final Testable<?, Long> testable = new Testable<>(ise);
372         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testLong, 1L));
373         assertSame(ise, e);
374         assertNull(testable.getAcceptedPrimitiveObject1());
375 
376         final Error error = new OutOfMemoryError();
377         testable.setThrowable(error);
378         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testLong, 1L));
379         assertSame(error, e);
380         assertNull(testable.getAcceptedPrimitiveObject1());
381 
382         final IOException ioe = new IOException("Unknown I/O error");
383         testable.setThrowable(ioe);
384         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testLong, 1L));
385         final Throwable t = e.getCause();
386         assertNotNull(t);
387         assertSame(ioe, t);
388         assertNull(testable.getAcceptedPrimitiveObject1());
389 
390         testable.setThrowable(null);
391         Functions.accept(testable::testLong, 1L);
392         assertEquals(1, testable.getAcceptedPrimitiveObject1());
393     }
394 
395     @Test
396     public void testAcceptObjDoubleConsumer() {
397         final IllegalStateException ise = new IllegalStateException();
398         final Testable<String, Double> testable = new Testable<>(ise);
399         Throwable e = assertThrows(IllegalStateException.class,
400             () -> Functions.accept(testable::testObjDouble, "X", 1d));
401         assertSame(ise, e);
402         assertNull(testable.getAcceptedObject());
403         assertNull(testable.getAcceptedPrimitiveObject1());
404 
405         final Error error = new OutOfMemoryError();
406         testable.setThrowable(error);
407         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjDouble, "X", 1d));
408         assertSame(error, e);
409         assertNull(testable.getAcceptedObject());
410         assertNull(testable.getAcceptedPrimitiveObject1());
411 
412         final IOException ioe = new IOException("Unknown I/O error");
413         testable.setThrowable(ioe);
414         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjDouble, "X", 1d));
415         final Throwable t = e.getCause();
416         assertNotNull(t);
417         assertSame(ioe, t);
418         assertNull(testable.getAcceptedObject());
419         assertNull(testable.getAcceptedPrimitiveObject1());
420 
421         testable.setThrowable(null);
422         Functions.accept(testable::testObjDouble, "X", 1d);
423         assertEquals("X", testable.getAcceptedObject());
424         assertEquals(1d, testable.getAcceptedPrimitiveObject1());
425     }
426 
427     @Test
428     public void testAcceptObjIntConsumer() {
429         final IllegalStateException ise = new IllegalStateException();
430         final Testable<String, Integer> testable = new Testable<>(ise);
431         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testObjInt, "X", 1));
432         assertSame(ise, e);
433         assertNull(testable.getAcceptedObject());
434         assertNull(testable.getAcceptedPrimitiveObject1());
435 
436         final Error error = new OutOfMemoryError();
437         testable.setThrowable(error);
438         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjInt, "X", 1));
439         assertSame(error, e);
440         assertNull(testable.getAcceptedObject());
441         assertNull(testable.getAcceptedPrimitiveObject1());
442 
443         final IOException ioe = new IOException("Unknown I/O error");
444         testable.setThrowable(ioe);
445         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjInt, "X", 1));
446         final Throwable t = e.getCause();
447         assertNotNull(t);
448         assertSame(ioe, t);
449         assertNull(testable.getAcceptedObject());
450         assertNull(testable.getAcceptedPrimitiveObject1());
451 
452         testable.setThrowable(null);
453         Functions.accept(testable::testObjInt, "X", 1);
454         assertEquals("X", testable.getAcceptedObject());
455         assertEquals(1, testable.getAcceptedPrimitiveObject1());
456     }
457 
458     @Test
459     public void testAcceptObjLongConsumer() {
460         final IllegalStateException ise = new IllegalStateException();
461         final Testable<String, Long> testable = new Testable<>(ise);
462         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testObjLong, "X", 1L));
463         assertSame(ise, e);
464         assertNull(testable.getAcceptedObject());
465         assertNull(testable.getAcceptedPrimitiveObject1());
466 
467         final Error error = new OutOfMemoryError();
468         testable.setThrowable(error);
469         e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjLong, "X", 1L));
470         assertSame(error, e);
471         assertNull(testable.getAcceptedObject());
472         assertNull(testable.getAcceptedPrimitiveObject1());
473 
474         final IOException ioe = new IOException("Unknown I/O error");
475         testable.setThrowable(ioe);
476         e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjLong, "X", 1L));
477         final Throwable t = e.getCause();
478         assertNotNull(t);
479         assertSame(ioe, t);
480         assertNull(testable.getAcceptedObject());
481         assertNull(testable.getAcceptedPrimitiveObject1());
482 
483         testable.setThrowable(null);
484         Functions.accept(testable::testObjLong, "X", 1L);
485         assertEquals("X", testable.getAcceptedObject());
486         assertEquals(1L, testable.getAcceptedPrimitiveObject1());
487     }
488 
489     @Test
490     public void testApplyBiFunction() {
491         final IllegalStateException ise = new IllegalStateException();
492         final Testable<?, ?> testable = new Testable<>(null);
493         Throwable e = assertThrows(IllegalStateException.class,
494             () -> Functions.apply(Testable::testAsInteger, testable, ise));
495         assertSame(ise, e);
496 
497         final Error error = new OutOfMemoryError();
498         e = assertThrows(OutOfMemoryError.class, () -> Functions.apply(Testable::testAsInteger, testable, error));
499         assertSame(error, e);
500 
501         final IOException ioe = new IOException("Unknown I/O error");
502         e = assertThrows(UncheckedIOException.class, () -> Functions.apply(Testable::testAsInteger, testable, ioe));
503         final Throwable t = e.getCause();
504         assertNotNull(t);
505         assertSame(ioe, t);
506 
507         final Integer i = Functions.apply(Testable::testAsInteger, testable, (Throwable) null);
508         assertNotNull(i);
509         assertEquals(0, i.intValue());
510     }
511 
512     @Test
513     public void testApplyFunction() {
514         final IllegalStateException ise = new IllegalStateException();
515         final Testable<?, ?> testable = new Testable<>(ise);
516         Throwable e = assertThrows(IllegalStateException.class,
517             () -> Functions.apply(Testable::testAsInteger, testable));
518         assertSame(ise, e);
519 
520         final Error error = new OutOfMemoryError();
521         testable.setThrowable(error);
522         e = assertThrows(OutOfMemoryError.class, () -> Functions.apply(Testable::testAsInteger, testable));
523         assertSame(error, e);
524 
525         final IOException ioe = new IOException("Unknown I/O error");
526         testable.setThrowable(ioe);
527         e = assertThrows(UncheckedIOException.class, () -> Functions.apply(Testable::testAsInteger, testable));
528         final Throwable t = e.getCause();
529         assertNotNull(t);
530         assertSame(ioe, t);
531 
532         testable.setThrowable(null);
533         final Integer i = Functions.apply(Testable::testAsInteger, testable);
534         assertNotNull(i);
535         assertEquals(0, i.intValue());
536     }
537 
538     @Test
539     public void testAsCallable() {
540         FailureOnOddInvocations.invocations = 0;
541         final FailableCallable<FailureOnOddInvocations, SomeException> failableCallable = FailureOnOddInvocations::new;
542         final Callable<FailureOnOddInvocations> callable = Functions.asCallable(failableCallable);
543         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, callable::call);
544         final Throwable cause = e.getCause();
545         assertNotNull(cause);
546         assertTrue(cause instanceof SomeException);
547         assertEquals("Odd Invocation: 1", cause.getMessage());
548         final FailureOnOddInvocations instance;
549         try {
550             instance = callable.call();
551         } catch (final Exception ex) {
552             throw Functions.rethrow(ex);
553         }
554         assertNotNull(instance);
555     }
556 
557     @Test
558     public void testAsConsumer() {
559         final IllegalStateException ise = new IllegalStateException();
560         final Testable<?, ?> testable = new Testable<>(ise);
561         final Consumer<Testable<?, ?>> consumer = Functions.asConsumer(Testable::test);
562         Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable));
563         assertSame(ise, e);
564 
565         final Error error = new OutOfMemoryError();
566         testable.setThrowable(error);
567         e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable));
568         assertSame(error, e);
569 
570         final IOException ioe = new IOException("Unknown I/O error");
571         testable.setThrowable(ioe);
572         e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable));
573         final Throwable t = e.getCause();
574         assertNotNull(t);
575         assertSame(ioe, t);
576 
577         testable.setThrowable(null);
578         Functions.accept(Testable::test, testable);
579     }
580 
581     @Test
582     public void testAsRunnable() {
583         FailureOnOddInvocations.invocations = 0;
584         final Runnable runnable = Functions.asRunnable(FailureOnOddInvocations::new);
585         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, runnable::run);
586         final Throwable cause = e.getCause();
587         assertNotNull(cause);
588         assertTrue(cause instanceof SomeException);
589         assertEquals("Odd Invocation: 1", cause.getMessage());
590 
591         // Even invocations, should not throw an exception
592         runnable.run();
593     }
594 
595     @Test
596     public void testAsSupplier() {
597         FailureOnOddInvocations.invocations = 0;
598         final FailableSupplier<FailureOnOddInvocations, Throwable> failableSupplier = FailureOnOddInvocations::new;
599         final Supplier<FailureOnOddInvocations> supplier = Functions.asSupplier(failableSupplier);
600         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, supplier::get);
601         final Throwable cause = e.getCause();
602         assertNotNull(cause);
603         assertTrue(cause instanceof SomeException);
604         assertEquals("Odd Invocation: 1", cause.getMessage());
605         assertNotNull(supplier.get());
606     }
607 
608     @Test
609     public void testBiConsumer() {
610         final IllegalStateException ise = new IllegalStateException();
611         final Testable<?, ?> testable = new Testable<>(null);
612         final FailableBiConsumer<Testable<?, ?>, Throwable, Throwable> failableBiConsumer = (t, th) -> {
613             t.setThrowable(th);
614             t.test();
615         };
616         final BiConsumer<Testable<?, ?>, Throwable> consumer = Functions.asBiConsumer(failableBiConsumer);
617         Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable, ise));
618         assertSame(ise, e);
619 
620         final Error error = new OutOfMemoryError();
621         e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable, error));
622         assertSame(error, e);
623 
624         final IOException ioe = new IOException("Unknown I/O error");
625         testable.setThrowable(ioe);
626         e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable, ioe));
627         final Throwable t = e.getCause();
628         assertNotNull(t);
629         assertSame(ioe, t);
630 
631         consumer.accept(testable, null);
632     }
633 
634     @Test
635     public void testBiFunction() {
636         final IllegalStateException ise = new IllegalStateException();
637         final Testable<?, ?> testable = new Testable<>(ise);
638         final FailableBiFunction<Testable<?, ?>, Throwable, Integer, Throwable> failableBiFunction = (t, th) -> {
639             t.setThrowable(th);
640             return Integer.valueOf(t.testAsInteger());
641         };
642         final BiFunction<Testable<?, ?>, Throwable, Integer> biFunction = Functions.asBiFunction(failableBiFunction);
643         Throwable e = assertThrows(IllegalStateException.class, () -> biFunction.apply(testable, ise));
644         assertSame(ise, e);
645 
646         final Error error = new OutOfMemoryError();
647         testable.setThrowable(error);
648         e = assertThrows(OutOfMemoryError.class, () -> biFunction.apply(testable, error));
649         assertSame(error, e);
650 
651         final IOException ioe = new IOException("Unknown I/O error");
652         testable.setThrowable(ioe);
653         e = assertThrows(UncheckedIOException.class, () -> biFunction.apply(testable, ioe));
654         final Throwable t = e.getCause();
655         assertNotNull(t);
656         assertSame(ioe, t);
657 
658         assertEquals(0, biFunction.apply(testable, null).intValue());
659     }
660 
661     @Test
662     @DisplayName("Test that asPredicate(FailableBiPredicate) is converted to -> BiPredicate ")
663     public void testBiPredicate() {
664         FailureOnOddInvocations.invocations = 0;
665         final Functions.FailableBiPredicate<Object, Object, Throwable> failableBiPredicate = (t1,
666             t2) -> FailureOnOddInvocations.failingBool();
667         final BiPredicate<?, ?> predicate = Functions.asBiPredicate(failableBiPredicate);
668         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class,
669             () -> predicate.test(null, null));
670         final Throwable cause = e.getCause();
671         assertNotNull(cause);
672         assertTrue(cause instanceof SomeException);
673         assertEquals("Odd Invocation: 1", cause.getMessage());
674         final boolean instance = predicate.test(null, null);
675         assertNotNull(instance);
676     }
677 
678     @Test
679     public void testCallable() {
680         FailureOnOddInvocations.invocations = 0;
681         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class,
682             () -> Functions.run(FailureOnOddInvocations::new));
683         final Throwable cause = e.getCause();
684         assertNotNull(cause);
685         assertTrue(cause instanceof SomeException);
686         assertEquals("Odd Invocation: 1", cause.getMessage());
687         final FailureOnOddInvocations instance = Functions.call(FailureOnOddInvocations::new);
688         assertNotNull(instance);
689     }
690 
691     @Test
692     public void testConstructor() {
693         // We allow this, which must have been an omission to make the ctor private.
694         // We could make the ctor private in 4.0.
695         new Functions();
696     }
697 
698     @Test
699     public void testFunction() {
700         final IllegalStateException ise = new IllegalStateException();
701         final Testable<?, ?> testable = new Testable<>(ise);
702         final FailableFunction<Throwable, Integer, Throwable> failableFunction = th -> {
703             testable.setThrowable(th);
704             return Integer.valueOf(testable.testAsInteger());
705         };
706         final Function<Throwable, Integer> function = Functions.asFunction(failableFunction);
707         Throwable e = assertThrows(IllegalStateException.class, () -> function.apply(ise));
708         assertSame(ise, e);
709 
710         final Error error = new OutOfMemoryError();
711         testable.setThrowable(error);
712         e = assertThrows(OutOfMemoryError.class, () -> function.apply(error));
713         assertSame(error, e);
714 
715         final IOException ioe = new IOException("Unknown I/O error");
716         testable.setThrowable(ioe);
717         e = assertThrows(UncheckedIOException.class, () -> function.apply(ioe));
718         final Throwable t = e.getCause();
719         assertNotNull(t);
720         assertSame(ioe, t);
721 
722         assertEquals(0, function.apply(null).intValue());
723     }
724 
725     @Test
726     public void testGetFromSupplier() {
727         FailureOnOddInvocations.invocations = 0;
728         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class,
729             () -> Functions.run(FailureOnOddInvocations::new));
730         final Throwable cause = e.getCause();
731         assertNotNull(cause);
732         assertTrue(cause instanceof SomeException);
733         assertEquals("Odd Invocation: 1", cause.getMessage());
734         final FailureOnOddInvocations instance = Functions.call(FailureOnOddInvocations::new);
735         assertNotNull(instance);
736     }
737 
738     @Test
739     public void testGetSupplier() {
740         final IllegalStateException ise = new IllegalStateException();
741         final Testable<?, ?> testable = new Testable<>(ise);
742         Throwable e = assertThrows(IllegalStateException.class, () -> Functions.get(testable::testAsInteger));
743         assertSame(ise, e);
744 
745         final Error error = new OutOfMemoryError();
746         testable.setThrowable(error);
747         e = assertThrows(OutOfMemoryError.class, () -> Functions.get(testable::testAsInteger));
748         assertSame(error, e);
749 
750         final IOException ioe = new IOException("Unknown I/O error");
751         testable.setThrowable(ioe);
752         e = assertThrows(UncheckedIOException.class, () -> Functions.get(testable::testAsInteger));
753         final Throwable t = e.getCause();
754         assertNotNull(t);
755         assertSame(ioe, t);
756 
757         testable.setThrowable(null);
758         final Integer i = Functions.apply(Testable::testAsInteger, testable);
759         assertNotNull(i);
760         assertEquals(0, i.intValue());
761     }
762 
763     @Test
764     @DisplayName("Test that asPredicate(FailablePredicate) is converted to -> Predicate ")
765     public void testPredicate() {
766         FailureOnOddInvocations.invocations = 0;
767         final Functions.FailablePredicate<Object, Throwable> failablePredicate = t -> FailureOnOddInvocations
768             .failingBool();
769         final Predicate<?> predicate = Functions.asPredicate(failablePredicate);
770         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class,
771             () -> predicate.test(null));
772         final Throwable cause = e.getCause();
773         assertNotNull(cause);
774         assertTrue(cause instanceof SomeException);
775         assertEquals("Odd Invocation: 1", cause.getMessage());
776         final boolean instance = predicate.test(null);
777         assertNotNull(instance);
778     }
779 
780     @Test
781     public void testRunnable() {
782         FailureOnOddInvocations.invocations = 0;
783         final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class,
784             () -> Functions.run(FailureOnOddInvocations::new));
785         final Throwable cause = e.getCause();
786         assertNotNull(cause);
787         assertTrue(cause instanceof SomeException);
788         assertEquals("Odd Invocation: 1", cause.getMessage());
789 
790         // Even invocations, should not throw an exception
791         Functions.run(FailureOnOddInvocations::new);
792     }
793 
794     /**
795      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
796      * Object and Throwable.
797      */
798     @Test
799     public void testThrows_FailableBiConsumer_Object_Throwable() {
800         new Functions.FailableBiConsumer<Object, Object, Throwable>() {
801 
802             @Override
803             public void accept(final Object object1, final Object object2) throws Throwable {
804                 throw new IOException("test");
805             }
806         };
807     }
808 
809     /**
810      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
811      * generic test types.
812      */
813     @Test
814     public void testThrows_FailableBiConsumer_String_IOException() {
815         new Functions.FailableBiConsumer<String, String, IOException>() {
816 
817             @Override
818             public void accept(final String object1, final String object2) throws IOException {
819                 throw new IOException("test");
820 
821             }
822         };
823     }
824 
825     /**
826      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
827      * Object and Throwable.
828      */
829     @Test
830     public void testThrows_FailableBiFunction_Object_Throwable() {
831         new Functions.FailableBiFunction<Object, Object, Object, Throwable>() {
832 
833             @Override
834             public Object apply(final Object input1, final Object input2) throws Throwable {
835                 throw new IOException("test");
836             }
837         };
838     }
839 
840     /**
841      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
842      * generic test types.
843      */
844     @Test
845     public void testThrows_FailableBiFunction_String_IOException() {
846         new Functions.FailableBiFunction<String, String, String, IOException>() {
847 
848             @Override
849             public String apply(final String input1, final String input2) throws IOException {
850                 throw new IOException("test");
851             }
852         };
853     }
854 
855     /**
856      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
857      * Object and Throwable.
858      */
859     @Test
860     public void testThrows_FailableBiPredicate_Object_Throwable() {
861         new Functions.FailableBiPredicate<Object, Object, Throwable>() {
862 
863             @Override
864             public boolean test(final Object object1, final Object object2) throws Throwable {
865                 throw new IOException("test");
866             }
867         };
868     }
869 
870     /**
871      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
872      * generic test types.
873      */
874     @Test
875     public void testThrows_FailableBiPredicate_String_IOException() {
876         new Functions.FailableBiPredicate<String, String, IOException>() {
877 
878             @Override
879             public boolean test(final String object1, final String object2) throws IOException {
880                 throw new IOException("test");
881             }
882         };
883     }
884 
885     /**
886      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
887      * Object and Throwable.
888      */
889     @Test
890     public void testThrows_FailableCallable_Object_Throwable() {
891         new Functions.FailableCallable<Object, Throwable>() {
892 
893             @Override
894             public Object call() throws Throwable {
895                 throw new IOException("test");
896             }
897         };
898     }
899 
900     /**
901      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
902      * generic test types.
903      */
904     @Test
905     public void testThrows_FailableCallable_String_IOException() {
906         new Functions.FailableCallable<String, IOException>() {
907 
908             @Override
909             public String call() throws IOException {
910                 throw new IOException("test");
911             }
912         };
913     }
914 
915     /**
916      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
917      * Object and Throwable.
918      */
919     @Test
920     public void testThrows_FailableConsumer_Object_Throwable() {
921         new Functions.FailableConsumer<Object, Throwable>() {
922 
923             @Override
924             public void accept(final Object object) throws Throwable {
925                 throw new IOException("test");
926 
927             }
928         };
929     }
930 
931     /**
932      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
933      * generic test types.
934      */
935     @Test
936     public void testThrows_FailableConsumer_String_IOException() {
937         new Functions.FailableConsumer<String, IOException>() {
938 
939             @Override
940             public void accept(final String object) throws IOException {
941                 throw new IOException("test");
942 
943             }
944         };
945     }
946 
947     /**
948      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
949      * Object and Throwable.
950      */
951     @Test
952     public void testThrows_FailableFunction_Object_Throwable() {
953         new Functions.FailableFunction<Object, Object, Throwable>() {
954 
955             @Override
956             public Object apply(final Object input) throws Throwable {
957                 throw new IOException("test");
958             }
959         };
960     }
961 
962     /**
963      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
964      * generic test types.
965      */
966     @Test
967     public void testThrows_FailableFunction_String_IOException() {
968         new Functions.FailableFunction<String, String, IOException>() {
969 
970             @Override
971             public String apply(final String input) throws IOException {
972                 throw new IOException("test");
973             }
974         };
975     }
976 
977     /**
978      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
979      * Object and Throwable.
980      */
981     @Test
982     public void testThrows_FailablePredicate_Object_Throwable() {
983         new Functions.FailablePredicate<Object, Throwable>() {
984 
985             @Override
986             public boolean test(final Object object) throws Throwable {
987                 throw new IOException("test");
988             }
989         };
990     }
991 
992     /**
993      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
994      * generic test types.
995      */
996     @Test
997     public void testThrows_FailablePredicate_String_IOException() {
998         new Functions.FailablePredicate<String, IOException>() {
999 
1000             @Override
1001             public boolean test(final String object) throws IOException {
1002                 throw new IOException("test");
1003             }
1004         };
1005     }
1006 
1007     /**
1008      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
1009      * Object and Throwable.
1010      */
1011     @Test
1012     public void testThrows_FailableRunnable_Object_Throwable() {
1013         new Functions.FailableRunnable<Throwable>() {
1014 
1015             @Override
1016             public void run() throws Throwable {
1017                 throw new IOException("test");
1018 
1019             }
1020         };
1021     }
1022 
1023     /**
1024      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
1025      * generic test types.
1026      */
1027     @Test
1028     public void testThrows_FailableRunnable_String_IOException() {
1029         new Functions.FailableRunnable<IOException>() {
1030 
1031             @Override
1032             public void run() throws IOException {
1033                 throw new IOException("test");
1034             }
1035         };
1036     }
1037 
1038     /**
1039      * Tests that our failable interface is properly defined to throw any exception. using the top level generic types
1040      * Object and Throwable.
1041      */
1042     @Test
1043     public void testThrows_FailableSupplier_Object_Throwable() {
1044         new Functions.FailableSupplier<Object, Throwable>() {
1045 
1046             @Override
1047             public Object get() throws Throwable {
1048                 throw new IOException("test");
1049             }
1050         };
1051     }
1052 
1053     /**
1054      * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as
1055      * generic test types.
1056      */
1057     @Test
1058     public void testThrows_FailableSupplier_String_IOException() {
1059         new Functions.FailableSupplier<String, IOException>() {
1060 
1061             @Override
1062             public String get() throws IOException {
1063                 throw new IOException("test");
1064             }
1065         };
1066     }
1067 
1068     @Test
1069     public void testTryWithResources() {
1070         final CloseableObject co = new CloseableObject();
1071         final FailableConsumer<Throwable, ? extends Throwable> consumer = co::run;
1072         final IllegalStateException ise = new IllegalStateException();
1073         Throwable e = assertThrows(IllegalStateException.class,
1074             () -> Functions.tryWithResources(() -> consumer.accept(ise), co::close));
1075         assertSame(ise, e);
1076 
1077         assertTrue(co.isClosed());
1078         co.reset();
1079         final Error error = new OutOfMemoryError();
1080         e = assertThrows(OutOfMemoryError.class,
1081             () -> Functions.tryWithResources(() -> consumer.accept(error), co::close));
1082         assertSame(error, e);
1083 
1084         assertTrue(co.isClosed());
1085         co.reset();
1086         final IOException ioe = new IOException("Unknown I/O error");
1087         final UncheckedIOException uioe = assertThrows(UncheckedIOException.class,
1088             () -> Functions.tryWithResources(() -> consumer.accept(ioe), co::close));
1089         final IOException cause = uioe.getCause();
1090         assertSame(ioe, cause);
1091 
1092         assertTrue(co.isClosed());
1093         co.reset();
1094         Functions.tryWithResources(() -> consumer.accept(null), co::close);
1095         assertTrue(co.isClosed());
1096     }
1097 }