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    *      https://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.io.input;
18  
19  import static org.apache.commons.io.IOUtils.EOF;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
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.assertThrowsExactly;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.io.ByteArrayInputStream;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.nio.charset.StandardCharsets;
31  import java.util.concurrent.atomic.AtomicBoolean;
32  
33  import org.apache.commons.io.IOUtils;
34  import org.apache.commons.io.test.CustomIOException;
35  import org.apache.commons.lang3.mutable.MutableInt;
36  import org.junit.jupiter.api.Test;
37  import org.junit.jupiter.params.ParameterizedTest;
38  import org.junit.jupiter.params.provider.ValueSource;
39  
40  /**
41   * Tests for {@link BoundedInputStream}.
42   */
43  class BoundedInputStreamTest {
44  
45      private void compare(final String message, final byte[] expected, final byte[] actual) {
46          assertEquals(expected.length, actual.length, () -> message + " (array length equals check)");
47          final MutableInt mi = new MutableInt();
48          for (int i = 0; i < expected.length; i++) {
49              mi.setValue(i);
50              assertEquals(expected[i], actual[i], () -> message + " byte[" + mi + "]");
51          }
52      }
53  
54      @Test
55      void testAfterReadConsumer() throws Exception {
56          final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
57          final AtomicBoolean boolRef = new AtomicBoolean();
58          // @formatter:off
59          try (InputStream bounded = BoundedInputStream.builder()
60                  .setInputStream(new ByteArrayInputStream(hello))
61                  .setMaxCount(hello.length)
62                  .setAfterRead(i -> boolRef.set(true))
63                  .get()) {
64              IOUtils.consume(bounded);
65          }
66          // @formatter:on
67          assertTrue(boolRef.get());
68          // Throwing
69          final String message = "test exception message";
70          // @formatter:off
71          try (InputStream bounded = BoundedInputStream.builder()
72                  .setInputStream(new ByteArrayInputStream(hello))
73                  .setMaxCount(hello.length)
74                  .setAfterRead(i -> {
75                      throw new CustomIOException(message);
76                  })
77                  .get()) {
78              assertEquals(message, assertThrowsExactly(CustomIOException.class, () -> IOUtils.consume(bounded)).getMessage());
79          }
80          // @formatter:on
81      }
82  
83      @SuppressWarnings("resource")
84      @Test
85      void testAvailableAfterClose() throws Exception {
86          final InputStream shadow;
87          try (InputStream in = BoundedInputStream.builder().setCharSequence("Hi").get()) {
88              assertTrue(in.available() > 0);
89              shadow = in;
90          }
91          assertEquals(0, shadow.available());
92      }
93  
94      @Test
95      void testAvailableAfterOpen() throws Exception {
96          try (InputStream in = BoundedInputStream.builder().setCharSequence("Hi").get()) {
97              assertTrue(in.available() > 0);
98          }
99      }
100 
101     @Test
102     void testBuilderGet() {
103         // java.lang.IllegalStateException: origin == null
104         assertThrows(IllegalStateException.class, () -> BoundedInputStream.builder().get());
105     }
106 
107     @Test
108     void testCloseHandleIOException() throws IOException {
109         ProxyInputStreamTest.testCloseHandleIOException(BoundedInputStream.builder());
110     }
111 
112     @ParameterizedTest
113     @ValueSource(longs = { -100, -1, 0, 1, 2, 4, 8, 16, 32, 64 })
114     void testCounts(final long startCount) throws Exception {
115         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
116         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
117         final long actualStart = startCount < 0 ? 0 : startCount;
118         // limit = length
119         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setCount(startCount)
120                 .setMaxCount(helloWorld.length).get()) {
121             assertTrue(bounded.markSupported());
122             assertEquals(helloWorld.length, bounded.getMaxCount());
123             assertEquals(helloWorld.length, bounded.getMaxLength());
124             assertEquals(actualStart, bounded.getCount());
125             assertEquals(Math.max(0, bounded.getMaxCount() - actualStart), bounded.getRemaining());
126             assertEquals(Math.max(0, bounded.getMaxLength() - actualStart), bounded.getRemaining());
127             int readCount = 0;
128             for (int i = 0; i < helloWorld.length; i++) {
129                 final byte expectedCh = bounded.getRemaining() > 0 ? helloWorld[i] : EOF;
130                 final int actualCh = bounded.read();
131                 assertEquals(expectedCh, actualCh, "limit = length byte[" + i + "]");
132                 if (actualCh != EOF) {
133                     readCount++;
134                 }
135                 assertEquals(helloWorld.length, bounded.getMaxCount());
136                 assertEquals(helloWorld.length, bounded.getMaxLength());
137                 assertEquals(actualStart + readCount, bounded.getCount(), "i=" + i);
138                 assertEquals(Math.max(0, bounded.getMaxCount() - (readCount + actualStart)), bounded.getRemaining());
139                 assertEquals(Math.max(0, bounded.getMaxLength() - (readCount + actualStart)), bounded.getRemaining());
140             }
141             assertEquals(-1, bounded.read(), "limit = length end");
142             assertEquals(helloWorld.length, bounded.getMaxLength());
143             assertEquals(readCount + actualStart, bounded.getCount());
144             assertEquals(0, bounded.getRemaining());
145             assertEquals(0, bounded.available());
146             // should be invariant
147             assertTrue(bounded.markSupported());
148         }
149         // limit > length
150         final int maxCountP1 = helloWorld.length + 1;
151         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setCount(startCount)
152                 .setMaxCount(maxCountP1).get()) {
153             assertTrue(bounded.markSupported());
154             assertEquals(maxCountP1, bounded.getMaxLength());
155             assertEquals(actualStart, bounded.getCount());
156             assertEquals(Math.max(0, bounded.getMaxCount() - actualStart), bounded.getRemaining());
157             assertEquals(Math.max(0, bounded.getMaxLength() - actualStart), bounded.getRemaining());
158             int readCount = 0;
159             for (int i = 0; i < helloWorld.length; i++) {
160                 final byte expectedCh = bounded.getRemaining() > 0 ? helloWorld[i] : EOF;
161                 final int actualCh = bounded.read();
162                 assertEquals(expectedCh, actualCh, "limit = length byte[" + i + "]");
163                 if (actualCh != EOF) {
164                     readCount++;
165                 }
166                 assertEquals(maxCountP1, bounded.getMaxCount());
167                 assertEquals(maxCountP1, bounded.getMaxLength());
168                 assertEquals(actualStart + readCount, bounded.getCount(), "i=" + i);
169                 assertEquals(Math.max(0, bounded.getMaxCount() - (readCount + actualStart)), bounded.getRemaining());
170                 assertEquals(Math.max(0, bounded.getMaxLength() - (readCount + actualStart)), bounded.getRemaining());
171             }
172             assertEquals(-1, bounded.read(), "limit > length end");
173             assertEquals(0, bounded.available());
174             assertEquals(maxCountP1, bounded.getMaxLength());
175             assertEquals(readCount + actualStart, bounded.getCount());
176             assertEquals(Math.max(0, maxCountP1 - bounded.getCount()), bounded.getRemaining());
177             // should be invariant
178             assertTrue(bounded.markSupported());
179         }
180         // limit < length
181         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(hello.length).get()) {
182             assertTrue(bounded.markSupported());
183             assertEquals(hello.length, bounded.getMaxLength());
184             assertEquals(0, bounded.getCount());
185             assertEquals(bounded.getMaxLength(), bounded.getRemaining());
186             int readCount = 0;
187             for (int i = 0; i < hello.length; i++) {
188                 assertEquals(hello[i], bounded.read(), "limit < length byte[" + i + "]");
189                 readCount++;
190                 assertEquals(hello.length, bounded.getMaxLength());
191                 assertEquals(readCount, bounded.getCount());
192                 assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
193             }
194             assertEquals(-1, bounded.read(), "limit < length end");
195             assertEquals(0, bounded.available());
196             assertEquals(hello.length, bounded.getMaxLength());
197             assertEquals(readCount, bounded.getCount());
198             assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
199             // should be invariant
200             assertTrue(bounded.markSupported());
201         }
202     }
203 
204     @Test
205     void testMarkReset() throws Exception {
206         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
207         final int helloWorldLen = helloWorld.length;
208         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
209         final byte[] world = " World".getBytes(StandardCharsets.UTF_8);
210         final int helloLen = hello.length;
211         // limit = -1
212         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).get()) {
213             assertTrue(bounded.markSupported());
214             bounded.mark(0);
215             compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
216             // should be invariant
217             assertTrue(bounded.markSupported());
218             // again
219             bounded.reset();
220             compare("limit = -1", hello, IOUtils.toByteArray(bounded, helloLen));
221             bounded.mark(helloWorldLen);
222             compare("limit = -1", world, IOUtils.toByteArray(bounded));
223             bounded.reset();
224             compare("limit = -1", world, IOUtils.toByteArray(bounded));
225             // should be invariant
226             assertTrue(bounded.markSupported());
227         }
228         // limit = 0
229         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(0).get()) {
230             assertTrue(bounded.markSupported());
231             bounded.mark(0);
232             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
233             // should be invariant
234             assertTrue(bounded.markSupported());
235             // again
236             bounded.reset();
237             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
238             bounded.mark(helloWorldLen);
239             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
240             // should be invariant
241             assertTrue(bounded.markSupported());
242         }
243         // limit = length
244         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
245                 .setMaxCount(helloWorld.length).get()) {
246             assertTrue(bounded.markSupported());
247             bounded.mark(0);
248             compare("limit = length", helloWorld, IOUtils.toByteArray(bounded));
249             // should be invariant
250             assertTrue(bounded.markSupported());
251             // again
252             bounded.reset();
253             compare("limit = length", hello, IOUtils.toByteArray(bounded, helloLen));
254             bounded.mark(helloWorldLen);
255             compare("limit = length", world, IOUtils.toByteArray(bounded));
256             bounded.reset();
257             compare("limit = length", world, IOUtils.toByteArray(bounded));
258             // should be invariant
259             assertTrue(bounded.markSupported());
260         }
261         // limit > length
262         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
263                 .setMaxCount(helloWorld.length + 1).get()) {
264             assertTrue(bounded.markSupported());
265             bounded.mark(0);
266             compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
267             // should be invariant
268             assertTrue(bounded.markSupported());
269             // again
270             bounded.reset();
271             compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
272             bounded.reset();
273             compare("limit > length", hello, IOUtils.toByteArray(bounded, helloLen));
274             bounded.mark(helloWorldLen);
275             compare("limit > length", world, IOUtils.toByteArray(bounded));
276             bounded.reset();
277             compare("limit > length", world, IOUtils.toByteArray(bounded));
278             // should be invariant
279             assertTrue(bounded.markSupported());
280         }
281         // limit < length
282         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
283                 .setMaxCount(helloWorld.length - (hello.length + 1)).get()) {
284             assertTrue(bounded.markSupported());
285             bounded.mark(0);
286             compare("limit < length", hello, IOUtils.toByteArray(bounded));
287             // should be invariant
288             assertTrue(bounded.markSupported());
289             // again
290             bounded.reset();
291             compare("limit < length", hello, IOUtils.toByteArray(bounded));
292             bounded.reset();
293             compare("limit < length", hello, IOUtils.toByteArray(bounded, helloLen));
294             bounded.mark(helloWorldLen);
295             compare("limit < length", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
296             bounded.reset();
297             compare("limit < length", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
298             // should be invariant
299             assertTrue(bounded.markSupported());
300         }
301     }
302 
303     @Test
304     void testOnMaxCountConsumer() throws Exception {
305         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
306         final AtomicBoolean boolRef = new AtomicBoolean();
307         // @formatter:off
308         try (BoundedInputStream bounded = BoundedInputStream.builder()
309                 .setInputStream(new ByteArrayInputStream(hello))
310                 .setMaxCount(hello.length)
311                 .setOnMaxCount(null) // should not blow up
312                 .setOnMaxCount((m, c) -> boolRef.set(true))
313                 .get()) {
314             IOUtils.consume(bounded);
315         }
316         // @formatter:on
317         assertTrue(boolRef.get());
318         // Throwing
319         final String message = "test exception message";
320         // @formatter:off
321         try (BoundedInputStream bounded = BoundedInputStream.builder()
322                 .setInputStream(new ByteArrayInputStream(hello))
323                 .setMaxCount(hello.length)
324                 .setOnMaxCount((m, c) -> {
325                     throw new CustomIOException(message);
326                 })
327                 .get()) {
328             assertEquals(message, assertThrowsExactly(CustomIOException.class, () -> IOUtils.consume(bounded)).getMessage());
329         }
330         // @formatter:on
331     }
332 
333     @SuppressWarnings("deprecation")
334     @Test
335     void testOnMaxLength() throws Exception {
336         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
337         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
338         final AtomicBoolean boolRef = new AtomicBoolean();
339         // limit = length
340         try (BoundedInputStream bounded = BoundedInputStream.builder()
341                 .setInputStream(new ByteArrayInputStream(helloWorld))
342                 .setMaxCount(helloWorld.length)
343                 .setOnMaxCount((m, c) -> boolRef.set(true))
344                 .get()) {
345             assertTrue(bounded.markSupported());
346             assertEquals(helloWorld.length, bounded.getMaxCount());
347             assertEquals(helloWorld.length, bounded.getMaxLength());
348             assertEquals(0, bounded.getCount());
349             assertEquals(bounded.getMaxCount(), bounded.getRemaining());
350             assertEquals(bounded.getMaxLength(), bounded.getRemaining());
351             assertFalse(boolRef.get());
352             int readCount = 0;
353             for (int i = 0; i < helloWorld.length; i++) {
354                 assertEquals(helloWorld[i], bounded.read(), "limit = length byte[" + i + "]");
355                 readCount++;
356                 assertEquals(helloWorld.length, bounded.getMaxCount());
357                 assertEquals(helloWorld.length, bounded.getMaxLength());
358                 assertEquals(readCount, bounded.getCount());
359                 assertEquals(bounded.getMaxCount() - readCount, bounded.getRemaining());
360                 assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
361             }
362             assertEquals(-1, bounded.read(), "limit = length end");
363             assertEquals(0, bounded.available());
364             assertEquals(helloWorld.length, bounded.getMaxLength());
365             assertEquals(readCount, bounded.getCount());
366             assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
367             assertTrue(boolRef.get());
368             // should be invariant
369             assertTrue(bounded.markSupported());
370         }
371         // limit > length
372         boolRef.set(false);
373         final int length2 = helloWorld.length + 1;
374         try (BoundedInputStream bounded = BoundedInputStream.builder()
375                 .setInputStream(new ByteArrayInputStream(helloWorld))
376                 .setMaxCount(length2)
377                 .setOnMaxCount((m, c) -> boolRef.set(true))
378                 .get()) {
379             assertTrue(bounded.markSupported());
380             assertEquals(length2, bounded.getMaxLength());
381             assertEquals(0, bounded.getCount());
382             assertEquals(bounded.getMaxLength(), bounded.getRemaining());
383             assertFalse(boolRef.get());
384             int readCount = 0;
385             for (int i = 0; i < helloWorld.length; i++) {
386                 assertEquals(helloWorld[i], bounded.read(), "limit > length byte[" + i + "]");
387                 readCount++;
388                 assertEquals(length2, bounded.getMaxLength());
389                 assertEquals(readCount, bounded.getCount());
390                 assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
391             }
392             assertEquals(0, bounded.available());
393             assertEquals(-1, bounded.read(), "limit > length end");
394             assertEquals(length2, bounded.getMaxLength());
395             assertEquals(readCount, bounded.getCount());
396             assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
397             assertFalse(boolRef.get());
398             // should be invariant
399             assertTrue(bounded.markSupported());
400         }
401         // limit < length
402         boolRef.set(false);
403         try (BoundedInputStream bounded = BoundedInputStream.builder()
404                 .setInputStream(new ByteArrayInputStream(helloWorld))
405                 .setMaxCount(hello.length)
406                 .setOnMaxCount((m, c) -> boolRef.set(true))
407                 .get()) {
408             assertTrue(bounded.markSupported());
409             assertEquals(hello.length, bounded.getMaxLength());
410             assertEquals(0, bounded.getCount());
411             assertEquals(bounded.getMaxLength(), bounded.getRemaining());
412             assertFalse(boolRef.get());
413             int readCount = 0;
414             for (int i = 0; i < hello.length; i++) {
415                 assertEquals(hello[i], bounded.read(), "limit < length byte[" + i + "]");
416                 readCount++;
417                 assertEquals(hello.length, bounded.getMaxLength());
418                 assertEquals(readCount, bounded.getCount());
419                 assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
420             }
421             assertEquals(-1, bounded.read(), "limit < length end");
422             assertEquals(hello.length, bounded.getMaxLength());
423             assertEquals(readCount, bounded.getCount());
424             assertEquals(bounded.getMaxLength() - readCount, bounded.getRemaining());
425             assertTrue(boolRef.get());
426             // should be invariant
427             assertTrue(bounded.markSupported());
428         }
429     }
430 
431     @SuppressWarnings("deprecation")
432     @Test
433     void testPublicConstructors() throws IOException {
434         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
435         try (ByteArrayInputStream baos = new ByteArrayInputStream(helloWorld);
436                 BoundedInputStream inputStream = new BoundedInputStream(baos)) {
437             assertSame(baos, inputStream.unwrap());
438         }
439         final long maxCount = 2;
440         try (ByteArrayInputStream baos = new ByteArrayInputStream(helloWorld);
441                 BoundedInputStream inputStream = new BoundedInputStream(baos, maxCount)) {
442             assertSame(baos, inputStream.unwrap());
443             assertSame(maxCount, inputStream.getMaxCount());
444         }
445     }
446 
447     @SuppressWarnings("resource")
448     @Test
449     void testReadAfterClose() throws Exception {
450         final InputStream shadow;
451         try (InputStream in = BoundedInputStream.builder().setCharSequence("Hi").get()) {
452             assertTrue(in.available() > 0);
453             shadow = in;
454         }
455         assertEquals(IOUtils.EOF, shadow.read());
456     }
457 
458     @Test
459     void testReadArray() throws Exception {
460         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
461         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
462         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).get()) {
463             assertTrue(bounded.markSupported());
464             compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
465             // should be invariant
466             assertTrue(bounded.markSupported());
467         }
468         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(0).get()) {
469             assertTrue(bounded.markSupported());
470             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
471             // should be invariant
472             assertTrue(bounded.markSupported());
473         }
474         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
475                 .setMaxCount(helloWorld.length).get()) {
476             assertTrue(bounded.markSupported());
477             compare("limit = length", helloWorld, IOUtils.toByteArray(bounded));
478             // should be invariant
479             assertTrue(bounded.markSupported());
480         }
481         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
482                 .setMaxCount(helloWorld.length + 1).get()) {
483             assertTrue(bounded.markSupported());
484             compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
485             // should be invariant
486             assertTrue(bounded.markSupported());
487         }
488         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
489                 .setMaxCount(helloWorld.length - 6).get()) {
490             assertTrue(bounded.markSupported());
491             compare("limit < length", hello, IOUtils.toByteArray(bounded));
492             // should be invariant
493             assertTrue(bounded.markSupported());
494         }
495     }
496 
497     @Test
498     void testReadSingle() throws Exception {
499         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
500         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
501         // limit = length
502         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(helloWorld.length)
503                 .get()) {
504             assertTrue(bounded.markSupported());
505             for (int i = 0; i < helloWorld.length; i++) {
506                 assertEquals(helloWorld[i], bounded.read(), "limit = length byte[" + i + "]");
507             }
508             assertEquals(-1, bounded.read(), "limit = length end");
509             // should be invariant
510             assertTrue(bounded.markSupported());
511         }
512         // limit > length
513         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(helloWorld.length + 1)
514                 .get()) {
515             assertTrue(bounded.markSupported());
516             for (int i = 0; i < helloWorld.length; i++) {
517                 assertEquals(helloWorld[i], bounded.read(), "limit > length byte[" + i + "]");
518             }
519             assertEquals(-1, bounded.read(), "limit > length end");
520             // should be invariant
521             assertTrue(bounded.markSupported());
522         }
523         // limit < length
524         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(hello.length).get()) {
525             assertTrue(bounded.markSupported());
526             for (int i = 0; i < hello.length; i++) {
527                 assertEquals(hello[i], bounded.read(), "limit < length byte[" + i + "]");
528             }
529             assertEquals(-1, bounded.read(), "limit < length end");
530             // should be invariant
531             assertTrue(bounded.markSupported());
532         }
533     }
534 
535     @Test
536     void testReset() throws Exception {
537         final byte[] helloWorld = "Hello World".getBytes(StandardCharsets.UTF_8);
538         final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
539         // limit = -1
540         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).get()) {
541             assertTrue(bounded.markSupported());
542             bounded.reset();
543             compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
544             // should be invariant
545             assertTrue(bounded.markSupported());
546             // again
547             bounded.reset();
548             compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
549             // should be invariant
550             assertTrue(bounded.markSupported());
551         }
552         // limit = 0
553         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld)).setMaxCount(0).get()) {
554             assertTrue(bounded.markSupported());
555             bounded.reset();
556             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
557             // should be invariant
558             assertTrue(bounded.markSupported());
559             // again
560             bounded.reset();
561             compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY, IOUtils.toByteArray(bounded));
562             // should be invariant
563             assertTrue(bounded.markSupported());
564         }
565         // limit = length
566         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
567                 .setMaxCount(helloWorld.length).get()) {
568             assertTrue(bounded.markSupported());
569             bounded.reset();
570             compare("limit = length", helloWorld, IOUtils.toByteArray(bounded));
571             // should be invariant
572             assertTrue(bounded.markSupported());
573             // again
574             bounded.reset();
575             compare("limit = length", helloWorld, IOUtils.toByteArray(bounded));
576             // should be invariant
577             assertTrue(bounded.markSupported());
578         }
579         // limit > length
580         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
581                 .setMaxCount(helloWorld.length + 1).get()) {
582             assertTrue(bounded.markSupported());
583             bounded.reset();
584             compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
585             // should be invariant
586             assertTrue(bounded.markSupported());
587             // again
588             bounded.reset();
589             compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
590             // should be invariant
591             assertTrue(bounded.markSupported());
592         }
593         // limit < length
594         try (BoundedInputStream bounded = BoundedInputStream.builder().setInputStream(new ByteArrayInputStream(helloWorld))
595                 .setMaxCount(helloWorld.length - 6).get()) {
596             assertTrue(bounded.markSupported());
597             bounded.reset();
598             compare("limit < length", hello, IOUtils.toByteArray(bounded));
599             // should be invariant
600             assertTrue(bounded.markSupported());
601             // again
602             bounded.reset();
603             compare("limit < length", hello, IOUtils.toByteArray(bounded));
604             // should be invariant
605             assertTrue(bounded.markSupported());
606         }
607     }
608 }