/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.lang3; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.UncheckedIOException; import java.lang.reflect.UndeclaredThrowableException; import java.util.concurrent.Callable; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import org.apache.commons.lang3.Functions.FailableBiConsumer; import org.apache.commons.lang3.Functions.FailableBiFunction; import org.apache.commons.lang3.Functions.FailableCallable; import org.apache.commons.lang3.Functions.FailableConsumer; import org.apache.commons.lang3.Functions.FailableFunction; import org.apache.commons.lang3.Functions.FailableSupplier; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class FunctionsTest extends AbstractLangTest { public static class CloseableObject { private boolean closed; public void close() { closed = true; } public boolean isClosed() { return closed; } public void reset() { closed = false; } public void run(final Throwable pTh) throws Throwable { if (pTh != null) { throw pTh; } } } public static class FailureOnOddInvocations { private static int invocations; static boolean failingBool() throws SomeException { throwOnOdd(); return true; } static boolean testDouble(final double value) throws SomeException { throwOnOdd(); return true; } static boolean testInt(final int value) throws SomeException { throwOnOdd(); return true; } static boolean testLong(final long value) throws SomeException { throwOnOdd(); return true; } private static void throwOnOdd() throws SomeException { final int i = ++invocations; if (i % 2 == 1) { throw new SomeException("Odd Invocation: " + i); } } FailureOnOddInvocations() throws SomeException { throwOnOdd(); } boolean getAsBoolean() throws SomeException { throwOnOdd(); return true; } } public static class SomeException extends Exception { private static final long serialVersionUID = -4965704778119283411L; private Throwable t; SomeException(final String message) { super(message); } public void setThrowable(final Throwable throwable) { t = throwable; } public void test() throws Throwable { if (t != null) { throw t; } } } public static class Testable { private T acceptedObject; private P acceptedPrimitiveObject1; private P acceptedPrimitiveObject2; private Throwable throwable; Testable(final Throwable throwable) { this.throwable = throwable; } public T getAcceptedObject() { return acceptedObject; } public P getAcceptedPrimitiveObject1() { return acceptedPrimitiveObject1; } public P getAcceptedPrimitiveObject2() { return acceptedPrimitiveObject2; } public void setThrowable(final Throwable throwable) { this.throwable = throwable; } public void test() throws Throwable { test(throwable); } public Object test(final Object input1, final Object input2) throws Throwable { test(throwable); return acceptedObject; } public void test(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } } public boolean testAsBooleanPrimitive() throws Throwable { return testAsBooleanPrimitive(throwable); } public boolean testAsBooleanPrimitive(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } return false; } public double testAsDoublePrimitive() throws Throwable { return testAsDoublePrimitive(throwable); } public double testAsDoublePrimitive(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } return 0; } public Integer testAsInteger() throws Throwable { return testAsInteger(throwable); } public Integer testAsInteger(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } return 0; } public int testAsIntPrimitive() throws Throwable { return testAsIntPrimitive(throwable); } public int testAsIntPrimitive(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } return 0; } public long testAsLongPrimitive() throws Throwable { return testAsLongPrimitive(throwable); } public long testAsLongPrimitive(final Throwable throwable) throws Throwable { if (throwable != null) { throw throwable; } return 0; } public void testDouble(final double i) throws Throwable { test(throwable); acceptedPrimitiveObject1 = (P) ((Double) i); } public double testDoubleDouble(final double i, final double j) throws Throwable { test(throwable); acceptedPrimitiveObject1 = (P) ((Double) i); acceptedPrimitiveObject2 = (P) ((Double) j); return 3d; } public void testInt(final int i) throws Throwable { test(throwable); acceptedPrimitiveObject1 = (P) ((Integer) i); } public void testLong(final long i) throws Throwable { test(throwable); acceptedPrimitiveObject1 = (P) ((Long) i); } public void testObjDouble(final T object, final double i) throws Throwable { test(throwable); acceptedObject = object; acceptedPrimitiveObject1 = (P) ((Double) i); } public void testObjInt(final T object, final int i) throws Throwable { test(throwable); acceptedObject = object; acceptedPrimitiveObject1 = (P) ((Integer) i); } public void testObjLong(final T object, final long i) throws Throwable { test(throwable); acceptedObject = object; acceptedPrimitiveObject1 = (P) ((Long) i); } } @Test public void testAcceptBiConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(null); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(Testable::test, testable, ise)); assertSame(ise, e); final Error error = new OutOfMemoryError(); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(Testable::test, testable, error)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(Testable::test, testable, ioe)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); testable.setThrowable(null); Functions.accept(Testable::test, testable, (Throwable) null); } @Test public void testAcceptConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(Testable::test, testable)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(Testable::test, testable)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(Testable::test, testable)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); testable.setThrowable(null); Functions.accept(Testable::test, testable); } @Test public void testAcceptDoubleConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testDouble, 1d)); assertSame(ise, e); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testDouble, 1d)); assertSame(error, e); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testDouble, 1d)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testDouble, 1d); assertEquals(1, testable.getAcceptedPrimitiveObject1()); } @Test public void testAcceptIntConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testInt, 1)); assertSame(ise, e); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testInt, 1)); assertSame(error, e); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testInt, 1)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testInt, 1); assertEquals(1, testable.getAcceptedPrimitiveObject1()); } @Test public void testAcceptLongConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testLong, 1L)); assertSame(ise, e); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testLong, 1L)); assertSame(error, e); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testLong, 1L)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testLong, 1L); assertEquals(1, testable.getAcceptedPrimitiveObject1()); } @Test public void testAcceptObjDoubleConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testObjDouble, "X", 1d)); assertSame(ise, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjDouble, "X", 1d)); assertSame(error, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjDouble, "X", 1d)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testObjDouble, "X", 1d); assertEquals("X", testable.getAcceptedObject()); assertEquals(1d, testable.getAcceptedPrimitiveObject1()); } @Test public void testAcceptObjIntConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testObjInt, "X", 1)); assertSame(ise, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjInt, "X", 1)); assertSame(error, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjInt, "X", 1)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testObjInt, "X", 1); assertEquals("X", testable.getAcceptedObject()); assertEquals(1, testable.getAcceptedPrimitiveObject1()); } @Test public void testAcceptObjLongConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.accept(testable::testObjLong, "X", 1L)); assertSame(ise, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.accept(testable::testObjLong, "X", 1L)); assertSame(error, e); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.accept(testable::testObjLong, "X", 1L)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertNull(testable.getAcceptedObject()); assertNull(testable.getAcceptedPrimitiveObject1()); testable.setThrowable(null); Functions.accept(testable::testObjLong, "X", 1L); assertEquals("X", testable.getAcceptedObject()); assertEquals(1L, testable.getAcceptedPrimitiveObject1()); } @Test public void testApplyBiFunction() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(null); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.apply(Testable::testAsInteger, testable, ise)); assertSame(ise, e); final Error error = new OutOfMemoryError(); e = assertThrows(OutOfMemoryError.class, () -> Functions.apply(Testable::testAsInteger, testable, error)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); e = assertThrows(UncheckedIOException.class, () -> Functions.apply(Testable::testAsInteger, testable, ioe)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); final Integer i = Functions.apply(Testable::testAsInteger, testable, (Throwable) null); assertNotNull(i); assertEquals(0, i.intValue()); } @Test public void testApplyFunction() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.apply(Testable::testAsInteger, testable)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.apply(Testable::testAsInteger, testable)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.apply(Testable::testAsInteger, testable)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); testable.setThrowable(null); final Integer i = Functions.apply(Testable::testAsInteger, testable); assertNotNull(i); assertEquals(0, i.intValue()); } @Test public void testAsCallable() { FailureOnOddInvocations.invocations = 0; final FailableCallable failableCallable = FailureOnOddInvocations::new; final Callable callable = Functions.asCallable(failableCallable); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, callable::call); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); final FailureOnOddInvocations instance; try { instance = callable.call(); } catch (final Exception ex) { throw Functions.rethrow(ex); } assertNotNull(instance); } @Test public void testAsConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); final Consumer> consumer = Functions.asConsumer(Testable::test); Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); testable.setThrowable(null); Functions.accept(Testable::test, testable); } @Test public void testAsRunnable() { FailureOnOddInvocations.invocations = 0; final Runnable runnable = Functions.asRunnable(FailureOnOddInvocations::new); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, runnable::run); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); // Even invocations, should not throw an exception runnable.run(); } @Test public void testAsSupplier() { FailureOnOddInvocations.invocations = 0; final FailableSupplier failableSupplier = FailureOnOddInvocations::new; final Supplier supplier = Functions.asSupplier(failableSupplier); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, supplier::get); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); assertNotNull(supplier.get()); } @Test public void testBiConsumer() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(null); final FailableBiConsumer, Throwable, Throwable> failableBiConsumer = (t, th) -> { t.setThrowable(th); t.test(); }; final BiConsumer, Throwable> consumer = Functions.asBiConsumer(failableBiConsumer); Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable, ise)); assertSame(ise, e); final Error error = new OutOfMemoryError(); e = assertThrows(OutOfMemoryError.class, () -> consumer.accept(testable, error)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> consumer.accept(testable, ioe)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); consumer.accept(testable, null); } @Test public void testBiFunction() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); final FailableBiFunction, Throwable, Integer, Throwable> failableBiFunction = (t, th) -> { t.setThrowable(th); return Integer.valueOf(t.testAsInteger()); }; final BiFunction, Throwable, Integer> biFunction = Functions.asBiFunction(failableBiFunction); Throwable e = assertThrows(IllegalStateException.class, () -> biFunction.apply(testable, ise)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> biFunction.apply(testable, error)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> biFunction.apply(testable, ioe)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertEquals(0, biFunction.apply(testable, null).intValue()); } @Test @DisplayName("Test that asPredicate(FailableBiPredicate) is converted to -> BiPredicate ") public void testBiPredicate() { FailureOnOddInvocations.invocations = 0; final Functions.FailableBiPredicate failableBiPredicate = (t1, t2) -> FailureOnOddInvocations.failingBool(); final BiPredicate predicate = Functions.asBiPredicate(failableBiPredicate); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> predicate.test(null, null)); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); final boolean instance = predicate.test(null, null); assertNotNull(instance); } @Test public void testCallable() { FailureOnOddInvocations.invocations = 0; final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> Functions.run(FailureOnOddInvocations::new)); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); final FailureOnOddInvocations instance = Functions.call(FailureOnOddInvocations::new); assertNotNull(instance); } @Test public void testConstructor() { // We allow this, which must have been an omission to make the ctor private. // We could make the ctor private in 4.0. new Functions(); } @Test public void testFunction() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); final FailableFunction failableFunction = th -> { testable.setThrowable(th); return Integer.valueOf(testable.testAsInteger()); }; final Function function = Functions.asFunction(failableFunction); Throwable e = assertThrows(IllegalStateException.class, () -> function.apply(ise)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> function.apply(error)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> function.apply(ioe)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); assertEquals(0, function.apply(null).intValue()); } @Test public void testGetFromSupplier() { FailureOnOddInvocations.invocations = 0; final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> Functions.run(FailureOnOddInvocations::new)); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); final FailureOnOddInvocations instance = Functions.call(FailureOnOddInvocations::new); assertNotNull(instance); } @Test public void testGetSupplier() { final IllegalStateException ise = new IllegalStateException(); final Testable testable = new Testable<>(ise); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.get(testable::testAsInteger)); assertSame(ise, e); final Error error = new OutOfMemoryError(); testable.setThrowable(error); e = assertThrows(OutOfMemoryError.class, () -> Functions.get(testable::testAsInteger)); assertSame(error, e); final IOException ioe = new IOException("Unknown I/O error"); testable.setThrowable(ioe); e = assertThrows(UncheckedIOException.class, () -> Functions.get(testable::testAsInteger)); final Throwable t = e.getCause(); assertNotNull(t); assertSame(ioe, t); testable.setThrowable(null); final Integer i = Functions.apply(Testable::testAsInteger, testable); assertNotNull(i); assertEquals(0, i.intValue()); } @Test @DisplayName("Test that asPredicate(FailablePredicate) is converted to -> Predicate ") public void testPredicate() { FailureOnOddInvocations.invocations = 0; final Functions.FailablePredicate failablePredicate = t -> FailureOnOddInvocations .failingBool(); final Predicate predicate = Functions.asPredicate(failablePredicate); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> predicate.test(null)); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); final boolean instance = predicate.test(null); assertNotNull(instance); } @Test public void testRunnable() { FailureOnOddInvocations.invocations = 0; final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> Functions.run(FailureOnOddInvocations::new)); final Throwable cause = e.getCause(); assertNotNull(cause); assertTrue(cause instanceof SomeException); assertEquals("Odd Invocation: 1", cause.getMessage()); // Even invocations, should not throw an exception Functions.run(FailureOnOddInvocations::new); } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableBiConsumer_Object_Throwable() { new Functions.FailableBiConsumer() { @Override public void accept(final Object object1, final Object object2) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableBiConsumer_String_IOException() { new Functions.FailableBiConsumer() { @Override public void accept(final String object1, final String object2) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableBiFunction_Object_Throwable() { new Functions.FailableBiFunction() { @Override public Object apply(final Object input1, final Object input2) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableBiFunction_String_IOException() { new Functions.FailableBiFunction() { @Override public String apply(final String input1, final String input2) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableBiPredicate_Object_Throwable() { new Functions.FailableBiPredicate() { @Override public boolean test(final Object object1, final Object object2) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableBiPredicate_String_IOException() { new Functions.FailableBiPredicate() { @Override public boolean test(final String object1, final String object2) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableCallable_Object_Throwable() { new Functions.FailableCallable() { @Override public Object call() throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableCallable_String_IOException() { new Functions.FailableCallable() { @Override public String call() throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableConsumer_Object_Throwable() { new Functions.FailableConsumer() { @Override public void accept(final Object object) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableConsumer_String_IOException() { new Functions.FailableConsumer() { @Override public void accept(final String object) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableFunction_Object_Throwable() { new Functions.FailableFunction() { @Override public Object apply(final Object input) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableFunction_String_IOException() { new Functions.FailableFunction() { @Override public String apply(final String input) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailablePredicate_Object_Throwable() { new Functions.FailablePredicate() { @Override public boolean test(final Object object) throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailablePredicate_String_IOException() { new Functions.FailablePredicate() { @Override public boolean test(final String object) throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableRunnable_Object_Throwable() { new Functions.FailableRunnable() { @Override public void run() throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableRunnable_String_IOException() { new Functions.FailableRunnable() { @Override public void run() throws IOException { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception. using the top level generic types * Object and Throwable. */ @Test public void testThrows_FailableSupplier_Object_Throwable() { new Functions.FailableSupplier() { @Override public Object get() throws Throwable { throw new IOException("test"); } }; } /** * Tests that our failable interface is properly defined to throw any exception using String and IOExceptions as * generic test types. */ @Test public void testThrows_FailableSupplier_String_IOException() { new Functions.FailableSupplier() { @Override public String get() throws IOException { throw new IOException("test"); } }; } @Test public void testTryWithResources() { final CloseableObject co = new CloseableObject(); final FailableConsumer consumer = co::run; final IllegalStateException ise = new IllegalStateException(); Throwable e = assertThrows(IllegalStateException.class, () -> Functions.tryWithResources(() -> consumer.accept(ise), co::close)); assertSame(ise, e); assertTrue(co.isClosed()); co.reset(); final Error error = new OutOfMemoryError(); e = assertThrows(OutOfMemoryError.class, () -> Functions.tryWithResources(() -> consumer.accept(error), co::close)); assertSame(error, e); assertTrue(co.isClosed()); co.reset(); final IOException ioe = new IOException("Unknown I/O error"); final UncheckedIOException uioe = assertThrows(UncheckedIOException.class, () -> Functions.tryWithResources(() -> consumer.accept(ioe), co::close)); final IOException cause = uioe.getCause(); assertSame(ioe, cause); assertTrue(co.isClosed()); co.reset(); Functions.tryWithResources(() -> consumer.accept(null), co::close); assertTrue(co.isClosed()); } }