1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.lang3;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.Closeable;
26 import java.io.IOException;
27 import java.util.Arrays;
28 import java.util.concurrent.atomic.AtomicBoolean;
29 import java.util.concurrent.atomic.AtomicReference;
30
31 import org.junit.jupiter.api.Test;
32
33
34
35
36 class AutoCloseablesTest extends AbstractLangTest {
37
38
39 private static class ThrowingCloseable implements Closeable {
40
41 private final IOException exception;
42
43 ThrowingCloseable(final IOException exception) {
44 this.exception = exception;
45 }
46
47 @Override
48 public void close() throws IOException {
49 throw exception;
50 }
51 }
52
53
54 private static class TrackingCloseable implements Closeable {
55
56 private final AtomicBoolean closed = new AtomicBoolean();
57
58 @Override
59 public void close() {
60 closed.set(true);
61 }
62
63 boolean isClosed() {
64 return closed.get();
65 }
66 }
67
68 @Test
69 void testClose_closesResource() throws Exception {
70 final TrackingCloseable tc = new TrackingCloseable();
71 AutoCloseables.close(tc);
72 assertTrue(tc.isClosed(), "Expected resource to be closed");
73 }
74
75 @Test
76 void testClose_null_doesNotThrow() throws Exception {
77 AutoCloseables.close((AutoCloseable) null);
78 }
79
80 @Test
81 void testClose_propagatesException() {
82 final IOException cause = new IOException("boom");
83 final ThrowingCloseable tc = new ThrowingCloseable(cause);
84 final Exception thrown = assertThrows(Exception.class, () -> AutoCloseables.close(tc));
85 assertEquals(cause, thrown);
86 }
87
88 @Test
89 void testClose_withConsumer_closesResource() throws Exception {
90 final TrackingCloseable tc = new TrackingCloseable();
91 AutoCloseables.close(tc, null);
92 assertTrue(tc.isClosed(), "Expected resource to be closed");
93 }
94
95 @Test
96 void testClose_withConsumer_exceptionDeliveredToConsumer() throws Exception {
97 final IOException cause = new IOException("boom");
98 final ThrowingCloseable tc = new ThrowingCloseable(cause);
99 final AtomicReference<Exception> received = new AtomicReference<>();
100 AutoCloseables.close(tc, received::set);
101 assertEquals(cause, received.get(), "Consumer should have received the exception");
102 }
103
104 @Test
105 void testClose_withConsumer_null_doesNotThrow() throws Exception {
106 AutoCloseables.close(null, null);
107 }
108
109 @Test
110 void testCloseQuietly_closesResource() {
111 final TrackingCloseable tc = new TrackingCloseable();
112 AutoCloseables.closeQuietly(tc);
113 assertTrue(tc.isClosed(), "Expected resource to be closed");
114 }
115
116 @Test
117 void testCloseQuietly_iterable_closesAllResources() {
118 final TrackingCloseable tc1 = new TrackingCloseable();
119 final TrackingCloseable tc2 = new TrackingCloseable();
120 AutoCloseables.closeQuietly(Arrays.asList(tc1, tc2));
121 assertTrue(tc1.isClosed(), "Expected first resource to be closed");
122 assertTrue(tc2.isClosed(), "Expected second resource to be closed");
123 }
124
125 @Test
126 void testCloseQuietly_iterable_null_doesNotThrow() {
127 AutoCloseables.closeQuietly((Iterable<AutoCloseable>) null);
128 }
129
130 @Test
131 void testCloseQuietly_iterable_swallowsExceptions() {
132 final ThrowingCloseable tc1 = new ThrowingCloseable(new IOException("first"));
133 final ThrowingCloseable tc2 = new ThrowingCloseable(new IOException("second"));
134 AutoCloseables.closeQuietly(Arrays.asList(tc1, tc2));
135 }
136
137 @Test
138 void testCloseQuietly_null_doesNotThrow() {
139 AutoCloseables.closeQuietly((AutoCloseable) null);
140 }
141
142 @Test
143 void testCloseQuietly_swallowsException() {
144 final ThrowingCloseable tc = new ThrowingCloseable(new IOException("ignored"));
145 AutoCloseables.closeQuietly(tc);
146 }
147
148 @Test
149 void testCloseQuietly_withConsumer_exceptionDeliveredToConsumer() {
150 final IOException cause = new IOException("boom");
151 final ThrowingCloseable tc = new ThrowingCloseable(cause);
152 final AtomicReference<Exception> received = new AtomicReference<>();
153 AutoCloseables.closeQuietly(tc, received::set);
154 assertEquals(cause, received.get(), "Consumer should have received the exception");
155 }
156
157 @Test
158 void testCloseQuietly_withConsumer_null_doesNotThrow() {
159 AutoCloseables.closeQuietly(null, (java.util.function.Consumer<Exception>) null);
160 }
161
162 @Test
163 void testCloseQuietly_withNullConsumer_swallowsException() {
164 final ThrowingCloseable tc = new ThrowingCloseable(new IOException("ignored"));
165 AutoCloseables.closeQuietly(tc, (java.util.function.Consumer<Exception>) null);
166 }
167
168 @Test
169 void testCloseQuietlySuppress_addsSuppressedException() {
170 final IOException closeException = new IOException("close failure");
171 final ThrowingCloseable tc = new ThrowingCloseable(closeException);
172 final RuntimeException primary = new RuntimeException("primary");
173 final RuntimeException result = AutoCloseables.closeQuietlySuppress(tc, primary);
174 assertEquals(primary, result);
175 assertNotNull(result.getSuppressed());
176 assertEquals(1, result.getSuppressed().length);
177 assertEquals(closeException, result.getSuppressed()[0]);
178 }
179
180 @Test
181 void testCloseQuietlySuppress_noException_returnsThrowable() throws Exception {
182 final TrackingCloseable tc = new TrackingCloseable();
183 final RuntimeException primary = new RuntimeException("primary");
184 final RuntimeException result = AutoCloseables.closeQuietlySuppress(tc, primary);
185 assertEquals(primary, result);
186 assertTrue(tc.isClosed());
187 assertEquals(0, result.getSuppressed().length, "No suppressed exceptions expected");
188 }
189
190 @Test
191 void testCloseQuietlySuppress_null_returnsThrowable() {
192 final RuntimeException primary = new RuntimeException("primary");
193 final RuntimeException result = AutoCloseables.closeQuietlySuppress(null, primary);
194 assertEquals(primary, result, "Should return the given throwable unchanged");
195 assertEquals(0, result.getSuppressed().length, "No suppressed exceptions expected");
196 }
197 }