blob: fad140b61f3ce49635a85036865dec16fe5972bb [file]
/*
* 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
*
* https://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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
/**
* Tests {@link AutoCloseables}.
*/
class AutoCloseablesTest extends AbstractLangTest {
/** An AutoCloseable that always throws on close(). */
private static class ThrowingCloseable implements Closeable {
private final IOException exception;
ThrowingCloseable(final IOException exception) {
this.exception = exception;
}
@Override
public void close() throws IOException {
throw exception;
}
}
/** An AutoCloseable that tracks whether close() was called. */
private static class TrackingCloseable implements Closeable {
private final AtomicBoolean closed = new AtomicBoolean();
@Override
public void close() {
closed.set(true);
}
boolean isClosed() {
return closed.get();
}
}
@Test
void testClose_closesResource() throws Exception {
final TrackingCloseable tc = new TrackingCloseable();
AutoCloseables.close(tc);
assertTrue(tc.isClosed(), "Expected resource to be closed");
}
@Test
void testClose_null_doesNotThrow() throws Exception {
AutoCloseables.close((AutoCloseable) null);
}
@Test
void testClose_propagatesException() {
final IOException cause = new IOException("boom");
final ThrowingCloseable tc = new ThrowingCloseable(cause);
final Exception thrown = assertThrows(Exception.class, () -> AutoCloseables.close(tc));
assertEquals(cause, thrown);
}
@Test
void testClose_withConsumer_closesResource() throws Exception {
final TrackingCloseable tc = new TrackingCloseable();
AutoCloseables.close(tc, null);
assertTrue(tc.isClosed(), "Expected resource to be closed");
}
@Test
void testClose_withConsumer_exceptionDeliveredToConsumer() throws Exception {
final IOException cause = new IOException("boom");
final ThrowingCloseable tc = new ThrowingCloseable(cause);
final AtomicReference<Exception> received = new AtomicReference<>();
AutoCloseables.close(tc, received::set);
assertEquals(cause, received.get(), "Consumer should have received the exception");
}
@Test
void testClose_withConsumer_null_doesNotThrow() throws Exception {
AutoCloseables.close(null, null);
}
@Test
void testCloseQuietly_closesResource() {
final TrackingCloseable tc = new TrackingCloseable();
AutoCloseables.closeQuietly(tc);
assertTrue(tc.isClosed(), "Expected resource to be closed");
}
@Test
void testCloseQuietly_iterable_closesAllResources() {
final TrackingCloseable tc1 = new TrackingCloseable();
final TrackingCloseable tc2 = new TrackingCloseable();
AutoCloseables.closeQuietly(Arrays.asList(tc1, tc2));
assertTrue(tc1.isClosed(), "Expected first resource to be closed");
assertTrue(tc2.isClosed(), "Expected second resource to be closed");
}
@Test
void testCloseQuietly_iterable_null_doesNotThrow() {
AutoCloseables.closeQuietly((Iterable<AutoCloseable>) null);
}
@Test
void testCloseQuietly_iterable_swallowsExceptions() {
final ThrowingCloseable tc1 = new ThrowingCloseable(new IOException("first"));
final ThrowingCloseable tc2 = new ThrowingCloseable(new IOException("second"));
AutoCloseables.closeQuietly(Arrays.asList(tc1, tc2));
}
@Test
void testCloseQuietly_null_doesNotThrow() {
AutoCloseables.closeQuietly((AutoCloseable) null);
}
@Test
void testCloseQuietly_swallowsException() {
final ThrowingCloseable tc = new ThrowingCloseable(new IOException("ignored"));
AutoCloseables.closeQuietly(tc);
}
@Test
void testCloseQuietly_withConsumer_exceptionDeliveredToConsumer() {
final IOException cause = new IOException("boom");
final ThrowingCloseable tc = new ThrowingCloseable(cause);
final AtomicReference<Exception> received = new AtomicReference<>();
AutoCloseables.closeQuietly(tc, received::set);
assertEquals(cause, received.get(), "Consumer should have received the exception");
}
@Test
void testCloseQuietly_withConsumer_null_doesNotThrow() {
AutoCloseables.closeQuietly(null, (java.util.function.Consumer<Exception>) null);
}
@Test
void testCloseQuietly_withNullConsumer_swallowsException() {
final ThrowingCloseable tc = new ThrowingCloseable(new IOException("ignored"));
AutoCloseables.closeQuietly(tc, (java.util.function.Consumer<Exception>) null);
}
@Test
void testCloseQuietlySuppress_addsSuppressedException() {
final IOException closeException = new IOException("close failure");
final ThrowingCloseable tc = new ThrowingCloseable(closeException);
final RuntimeException primary = new RuntimeException("primary");
final RuntimeException result = AutoCloseables.closeQuietlySuppress(tc, primary);
assertEquals(primary, result);
assertNotNull(result.getSuppressed());
assertEquals(1, result.getSuppressed().length);
assertEquals(closeException, result.getSuppressed()[0]);
}
@Test
void testCloseQuietlySuppress_noException_returnsThrowable() throws Exception {
final TrackingCloseable tc = new TrackingCloseable();
final RuntimeException primary = new RuntimeException("primary");
final RuntimeException result = AutoCloseables.closeQuietlySuppress(tc, primary);
assertEquals(primary, result);
assertTrue(tc.isClosed());
assertEquals(0, result.getSuppressed().length, "No suppressed exceptions expected");
}
@Test
void testCloseQuietlySuppress_null_returnsThrowable() {
final RuntimeException primary = new RuntimeException("primary");
final RuntimeException result = AutoCloseables.closeQuietlySuppress(null, primary);
assertEquals(primary, result, "Should return the given throwable unchanged");
assertEquals(0, result.getSuppressed().length, "No suppressed exceptions expected");
}
}