1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.io.input;
19
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.assertNotEquals;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertSame;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.verify;
31
32 import java.io.ByteArrayInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.nio.charset.StandardCharsets;
36 import java.nio.file.Files;
37 import java.nio.file.Paths;
38 import java.util.Arrays;
39 import java.util.concurrent.atomic.AtomicBoolean;
40
41 import org.apache.commons.io.IOUtils;
42 import org.apache.commons.io.build.AbstractStreamBuilder;
43 import org.apache.commons.io.test.CustomIOException;
44 import org.junit.jupiter.api.Test;
45
46
47
48
49
50
51 public class ProxyInputStreamTest<T extends ProxyInputStream> {
52
53 private static final class ProxyInputStreamFixture extends ProxyInputStream {
54
55 static class Builder extends ProxyInputStream.AbstractBuilder<ProxyInputStreamFixture, Builder> {
56
57 @Override
58 public ProxyInputStreamFixture get() throws IOException {
59 return new ProxyInputStreamFixture(this);
60 }
61
62 }
63
64 static Builder builder() {
65 return new Builder();
66 }
67
68 ProxyInputStreamFixture(final Builder builder) throws IOException {
69 super(builder);
70 }
71
72 ProxyInputStreamFixture(final InputStream proxy) {
73 super(proxy);
74 }
75 }
76
77 @SuppressWarnings("resource")
78 static <T, B extends AbstractStreamBuilder<T, B>> void testCloseHandleIOException(final AbstractStreamBuilder<T, B> builder) throws IOException {
79 final IOException exception = new IOException();
80 testCloseHandleIOException((ProxyInputStream) builder.setInputStream(new BrokenInputStream(() -> exception)).get());
81 }
82
83 @SuppressWarnings("resource")
84 static void testCloseHandleIOException(final ProxyInputStream inputStream) throws IOException {
85 assertFalse(inputStream.isClosed(), "closed");
86 final ProxyInputStream spy = spy(inputStream);
87 assertThrows(IOException.class, spy::close);
88 final BrokenInputStream unwrap = (BrokenInputStream) inputStream.unwrap();
89 verify(spy).handleIOException((IOException) unwrap.getThrowable());
90 assertFalse(spy.isClosed(), "closed");
91 }
92
93
94
95
96
97
98 @SuppressWarnings("resource")
99 protected void assertMarkSupportedEquals(final ProxyInputStream inputStream) {
100 assertNotNull(inputStream, "inputStream");
101 assertEquals(inputStream.unwrap().markSupported(), inputStream.markSupported());
102 }
103
104 @SuppressWarnings({ "resource", "unused", "unchecked" })
105 protected T createFixture() throws IOException {
106 return (T) new ProxyInputStreamFixture(createOriginInputStream());
107 }
108
109 @SuppressWarnings("unchecked")
110 protected T createFixture(final InputStream proxy) {
111 return (T) new ProxyInputStreamFixture(proxy);
112 }
113
114 protected InputStream createOriginInputStream() {
115 return CharSequenceInputStream.builder().setCharSequence("abc").get();
116 }
117
118 @SuppressWarnings("resource")
119 @Test
120 void testAvailableAfterClose() throws IOException {
121 final T shadow;
122 try (T inputStream = createFixture()) {
123 shadow = inputStream;
124 }
125 assertEquals(0, shadow.available());
126 }
127
128 @Test
129 void testAvailableAfterOpen() throws IOException {
130 try (T inputStream = createFixture()) {
131 assertEquals(3, inputStream.available());
132 }
133 }
134
135 @Test
136 void testAvailableAll() throws IOException {
137 try (T inputStream = createFixture()) {
138 assertEquals(3, inputStream.available());
139 IOUtils.toByteArray(inputStream);
140 assertEquals(0, inputStream.available());
141 }
142 }
143
144 @Test
145 void testAvailableNull() throws IOException {
146 try (T inputStream = createFixture(null)) {
147 assertEquals(0, inputStream.available());
148 inputStream.setReference(createFixture());
149 assertEquals(3, inputStream.available());
150 IOUtils.toByteArray(inputStream);
151 assertEquals(0, inputStream.available());
152 inputStream.setReference(null);
153 assertEquals(0, inputStream.available());
154 }
155 }
156
157 protected void testEos(final T inputStream) {
158
159 }
160
161
162 void testMarkOnNull() throws IOException {
163 try (T inputStream = createFixture(null)) {
164 inputStream.mark(1);
165 inputStream.setReference(createFixture());
166 inputStream.mark(1);
167 IOUtils.toByteArray(inputStream);
168 inputStream.mark(1);
169 inputStream.setReference(null);
170 inputStream.mark(1);
171 }
172 }
173
174 @Test
175 void testMarkSupported() throws IOException {
176 try (T inputStream = createFixture()) {
177 assertMarkSupportedEquals(inputStream);
178 }
179 }
180
181 @SuppressWarnings("resource")
182 @Test
183 void testMarkSupportedAfterClose() throws IOException {
184 final T shadow;
185 try (T inputStream = createFixture()) {
186 shadow = inputStream;
187 }
188 assertMarkSupportedEquals(shadow);
189 }
190
191 @Test
192 void testMarkSupportedOnNull() throws IOException {
193 try (ProxyInputStream fixture = createFixture()) {
194 assertMarkSupportedEquals(fixture);
195 fixture.setReference(null);
196 assertFalse(fixture.markSupported());
197 }
198 }
199
200 @Test
201 void testRead() throws IOException {
202 try (T inputStream = createFixture()) {
203 int found = inputStream.read();
204 assertEquals('a', found);
205 found = inputStream.read();
206 assertEquals('b', found);
207 found = inputStream.read();
208 assertEquals('c', found);
209 found = inputStream.read();
210 assertEquals(-1, found);
211 testEos(inputStream);
212 }
213 }
214
215 @Test
216 void testReadAfterClose_ByteArrayInputStream() throws IOException {
217 try (InputStream inputStream = new ProxyInputStreamFixture(new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8)))) {
218 inputStream.close();
219
220 assertNotEquals(IOUtils.EOF, inputStream.read());
221 }
222 }
223
224 @Test
225 void testReadAfterClose_ChannelInputStream() throws IOException {
226 try (InputStream inputStream = new ProxyInputStreamFixture(
227 Files.newInputStream(Paths.get("src/test/resources/org/apache/commons/io/abitmorethan16k.txt")))) {
228 inputStream.close();
229
230 assertThrows(IOException.class, inputStream::read);
231 }
232 }
233
234 @Test
235 void testReadAfterClose_CharSequenceInputStream() throws IOException {
236 try (InputStream inputStream = createFixture()) {
237 inputStream.close();
238
239 assertEquals(IOUtils.EOF, inputStream.read());
240 }
241 }
242
243 @Test
244 void testReadArrayAtMiddleFully() throws IOException {
245 try (T inputStream = createFixture()) {
246 final byte[] dest = new byte[5];
247 int found = inputStream.read(dest, 2, 3);
248 assertEquals(3, found);
249 assertArrayEquals(new byte[] { 0, 0, 'a', 'b', 'c' }, dest);
250 found = inputStream.read(dest, 2, 3);
251 assertEquals(-1, found);
252 testEos(inputStream);
253 }
254 }
255
256 @Test
257 void testReadArrayAtStartFully() throws IOException {
258 try (T inputStream = createFixture()) {
259 final byte[] dest = new byte[5];
260 int found = inputStream.read(dest, 0, 5);
261 assertEquals(3, found);
262 assertArrayEquals(new byte[] { 'a', 'b', 'c', 0, 0 }, dest);
263 found = inputStream.read(dest, 0, 5);
264 assertEquals(-1, found);
265 testEos(inputStream);
266 }
267 }
268
269 @Test
270 void testReadArrayAtStartPartial() throws IOException {
271 try (T inputStream = createFixture()) {
272 final byte[] dest = new byte[5];
273 int found = inputStream.read(dest, 0, 2);
274 assertEquals(2, found);
275 assertArrayEquals(new byte[] { 'a', 'b', 0, 0, 0 }, dest);
276 Arrays.fill(dest, (byte) 0);
277 found = inputStream.read(dest, 0, 2);
278 assertEquals(1, found);
279 assertArrayEquals(new byte[] { 'c', 0, 0, 0, 0 }, dest);
280 found = inputStream.read(dest, 0, 2);
281 assertEquals(-1, found);
282 testEos(inputStream);
283 }
284 }
285
286 @Test
287 void testReadArrayFully() throws IOException {
288 try (T inputStream = createFixture()) {
289 final byte[] dest = new byte[5];
290 int found = inputStream.read(dest);
291 assertEquals(3, found);
292 assertArrayEquals(new byte[] { 'a', 'b', 'c', 0, 0 }, dest);
293 found = inputStream.read(dest);
294 assertEquals(-1, found);
295 testEos(inputStream);
296 }
297 }
298
299 @Test
300 void testReadArrayPartial() throws IOException {
301 try (T inputStream = createFixture()) {
302 final byte[] dest = new byte[2];
303 int found = inputStream.read(dest);
304 assertEquals(2, found);
305 assertArrayEquals(new byte[] { 'a', 'b' }, dest);
306 Arrays.fill(dest, (byte) 0);
307 found = inputStream.read(dest);
308 assertEquals(1, found);
309 assertArrayEquals(new byte[] { 'c', 0 }, dest);
310 found = inputStream.read(dest);
311 assertEquals(-1, found);
312 testEos(inputStream);
313 }
314 }
315
316 @Test
317 void testReadEof() throws Exception {
318 final ByteArrayInputStream proxy = new ByteArrayInputStream(new byte[2]);
319 try (ProxyInputStream inputStream = new ProxyInputStreamFixture(proxy)) {
320 assertSame(proxy, inputStream.unwrap());
321 int found = inputStream.read();
322 assertEquals(0, found);
323 found = inputStream.read();
324 assertEquals(0, found);
325 found = inputStream.read();
326 assertEquals(-1, found);
327 }
328 }
329
330 @Test
331 void testSubclassAfterReadConsumer() throws Exception {
332 final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
333 final AtomicBoolean boolRef = new AtomicBoolean();
334
335 try (ProxyInputStreamFixture bounded = ProxyInputStreamFixture.builder()
336 .setInputStream(new ByteArrayInputStream(hello))
337 .setAfterRead(null)
338 .setAfterRead(i -> boolRef.set(true))
339 .get()) {
340 IOUtils.consume(bounded);
341 }
342
343 assertTrue(boolRef.get());
344
345 final String message = "test exception message";
346
347 try (ProxyInputStreamFixture bounded = ProxyInputStreamFixture.builder()
348 .setInputStream(new ByteArrayInputStream(hello))
349 .setAfterRead(i -> {
350 throw new CustomIOException(message);
351 })
352 .get()) {
353 assertEquals(message, assertThrowsExactly(CustomIOException.class, () -> IOUtils.consume(bounded)).getMessage());
354 }
355
356 }
357
358 }