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.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  
27  import org.junit.jupiter.api.Test;
28  import org.junit.jupiter.params.ParameterizedTest;
29  import org.junit.jupiter.params.provider.MethodSource;
30  
31  /**
32   * Tests {@link MarkShieldInputStream}.
33   */
34  class MarkShieldInputStreamTest {
35  
36      private static final class MarkTestableInputStream extends ProxyInputStream {
37          int markcount;
38          int readLimit;
39  
40          MarkTestableInputStream(final InputStream in) {
41              super(in);
42          }
43  
44          @SuppressWarnings("sync-override")
45          @Override
46          public void mark(final int readLimit) {
47              // record that `mark` was called
48              this.markcount++;
49              this.readLimit = readLimit;
50              // invoke on super
51              super.mark(readLimit);
52          }
53      }
54  
55      @SuppressWarnings("resource")
56      @ParameterizedTest
57      @MethodSource(AbstractInputStreamTest.ARRAY_LENGTHS_NAME)
58      void testAvailableAfterClose(final int len) throws Exception {
59          final InputStream shadow;
60          try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(len, false, false));
61                  MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
62              assertEquals(len, in.available());
63              shadow = in;
64          }
65          assertEquals(0, shadow.available());
66      }
67  
68      @ParameterizedTest
69      @MethodSource(AbstractInputStreamTest.ARRAY_LENGTHS_NAME)
70      void testAvailableAfterOpen(final int len) throws Exception {
71          try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(len, false, false));
72                  MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
73              assertEquals(len, in.available());
74          }
75      }
76  
77      @SuppressWarnings("resource")
78      @Test
79      void testCloseHandleIOException() throws IOException {
80          ProxyInputStreamTest.testCloseHandleIOException(new MarkShieldInputStream(new BrokenInputStream((Throwable) new IOException())));
81      }
82  
83      @Test
84      void testMarkIsNoOpWhenUnderlyingDoesNotSupport() throws IOException {
85          try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(64, false, false));
86                  MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
87              msis.mark(1024);
88              assertEquals(0, in.markcount);
89              assertEquals(0, in.readLimit);
90          }
91      }
92  
93      @Test
94      void testMarkIsNoOpWhenUnderlyingSupports() throws IOException {
95          try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(64, true, false));
96                  MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
97              msis.mark(1024);
98              assertEquals(0, in.markcount);
99              assertEquals(0, in.readLimit);
100         }
101     }
102 
103     @Test
104     void testMarkSupportedIsFalseWhenUnderlyingFalse() throws IOException {
105         // test wrapping an underlying stream which does NOT support marking
106         try (InputStream is = new NullInputStream(64, false, false)) {
107             assertFalse(is.markSupported());
108             try (MarkShieldInputStream msis = new MarkShieldInputStream(is)) {
109                 assertFalse(msis.markSupported());
110             }
111         }
112     }
113 
114     @Test
115     void testMarkSupportedIsFalseWhenUnderlyingTrue() throws IOException {
116         // test wrapping an underlying stream which supports marking
117         try (InputStream is = new NullInputStream(64, true, false)) {
118             assertTrue(is.markSupported());
119             try (MarkShieldInputStream msis = new MarkShieldInputStream(is)) {
120                 assertFalse(msis.markSupported());
121             }
122         }
123     }
124 
125     @ParameterizedTest
126     @MethodSource(AbstractInputStreamTest.ARRAY_LENGTHS_NAME)
127     void testReadAfterClose(final int len) throws Exception {
128         try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(len, false, false));
129                 MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
130             assertEquals(len, in.available());
131             in.close();
132             assertThrows(IOException.class, in::read);
133         }
134     }
135 
136     @ParameterizedTest
137     @MethodSource(AbstractInputStreamTest.ARRAY_LENGTHS_NAME)
138     void testReadByteArrayAfterClose(final int len) throws Exception {
139         try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(len, false, false));
140                 MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
141             assertEquals(len, in.available());
142             in.close();
143             assertEquals(0, in.read(new byte[0]));
144             assertThrows(IOException.class, () -> in.read(new byte[2]));
145         }
146     }
147 
148     @ParameterizedTest
149     @MethodSource(AbstractInputStreamTest.ARRAY_LENGTHS_NAME)
150     void testReadByteArrayIntIntAfterClose(final int len) throws Exception {
151         try (MarkTestableInputStream in = new MarkTestableInputStream(new NullInputStream(len, false, false));
152                 MarkShieldInputStream msis = new MarkShieldInputStream(in)) {
153             assertEquals(len, in.available());
154             in.close();
155             assertEquals(0, in.read(new byte[0], 0, 1));
156             assertEquals(0, in.read(new byte[1], 0, 0));
157             assertThrows(IOException.class, () -> in.read(new byte[2], 0, 1));
158         }
159     }
160 
161     @Test
162     void testResetThrowsExceptionWhenUnderlyingDoesNotSupport() throws IOException {
163         // test wrapping an underlying stream which does NOT support marking
164         try (MarkShieldInputStream msis = new MarkShieldInputStream(new NullInputStream(64, false, false))) {
165             assertThrows(UnsupportedOperationException.class, msis::reset);
166         }
167     }
168 
169     @Test
170     void testResetThrowsExceptionWhenUnderlyingSupports() throws IOException {
171         // test wrapping an underlying stream which supports marking
172         try (MarkShieldInputStream msis = new MarkShieldInputStream(new NullInputStream(64, true, false))) {
173             assertThrows(UnsupportedOperationException.class, msis::reset);
174         }
175     }
176 }