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.assertThrows;
21  import static org.mockito.Mockito.mock;
22  import static org.mockito.Mockito.never;
23  import static org.mockito.Mockito.times;
24  import static org.mockito.Mockito.verify;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.ByteArrayOutputStream;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.OutputStream;
31  import java.nio.charset.StandardCharsets;
32  
33  import org.apache.commons.io.test.ThrowOnCloseInputStream;
34  import org.apache.commons.io.test.ThrowOnCloseOutputStream;
35  import org.junit.jupiter.api.BeforeEach;
36  import org.junit.jupiter.api.Test;
37  
38  /**
39   * Tests {@link TeeInputStream}.
40   */
41  class TeeInputStreamTest  {
42  
43      private final String ASCII = StandardCharsets.US_ASCII.name();
44  
45      private InputStream tee;
46  
47      private ByteArrayOutputStream output;
48  
49      @BeforeEach
50      public void setUp() throws Exception {
51          final InputStream input = new ByteArrayInputStream("abc".getBytes(ASCII));
52          output = new ByteArrayOutputStream();
53          tee = new TeeInputStream(input, output);
54      }
55  
56      /**
57       * Tests that the main {@code InputStream} is closed when closing the branch {@code OutputStream} throws an
58       * exception on {@link TeeInputStream#close()}, if specified to do so.
59       */
60      @Test
61      void testCloseBranchIOException() throws Exception {
62          final ByteArrayInputStream goodIs = mock(ByteArrayInputStream.class);
63          final OutputStream badOs = new ThrowOnCloseOutputStream();
64  
65          final TeeInputStream nonClosingTis = new TeeInputStream(goodIs, badOs, false);
66          nonClosingTis.close();
67          verify(goodIs).close();
68  
69          final TeeInputStream closingTis = new TeeInputStream(goodIs, badOs, true);
70          assertThrows(IOException.class, closingTis::close);
71          verify(goodIs, times(2)).close();
72      }
73  
74      @SuppressWarnings({ "resource" })
75      @Test
76      void testCloseHandleIOException() throws IOException {
77          ProxyInputStreamTest
78                  .testCloseHandleIOException(new TeeInputStream(new BrokenInputStream((Throwable) new IOException()), new ByteArrayOutputStream(), false));
79          ProxyInputStreamTest
80                  .testCloseHandleIOException(new TeeInputStream(new BrokenInputStream((Throwable) new IOException()), new ByteArrayOutputStream(), true));
81      }
82  
83      /**
84       * Tests that the branch {@code OutputStream} is closed when closing the main {@code InputStream} throws an
85       * exception on {@link TeeInputStream#close()}, if specified to do so.
86       */
87      @Test
88      void testCloseMainIOException() throws IOException {
89          final InputStream badIs = new ThrowOnCloseInputStream();
90          final ByteArrayOutputStream goodOs = mock(ByteArrayOutputStream.class);
91  
92          final TeeInputStream nonClosingTis = new TeeInputStream(badIs, goodOs, false);
93          assertThrows(IOException.class, nonClosingTis::close);
94          verify(goodOs, never()).close();
95  
96          final TeeInputStream closingTis = new TeeInputStream(badIs, goodOs, true);
97          assertThrows(IOException.class, closingTis::close);
98          verify(goodOs).close();
99      }
100 
101     @Test
102     void testMarkReset() throws Exception {
103         assertEquals('a', tee.read());
104         tee.mark(1);
105         assertEquals('b', tee.read());
106         tee.reset();
107         assertEquals('b', tee.read());
108         assertEquals('c', tee.read());
109         assertEquals(-1, tee.read());
110         assertEquals("abbc", output.toString(ASCII));
111     }
112 
113     @Test
114     void testReadEverything() throws Exception {
115         assertEquals('a', tee.read());
116         assertEquals('b', tee.read());
117         assertEquals('c', tee.read());
118         assertEquals(-1, tee.read());
119         assertEquals("abc", output.toString(ASCII));
120     }
121 
122     @Test
123     void testReadNothing() throws Exception {
124         assertEquals("", output.toString(ASCII));
125     }
126 
127     @Test
128     void testReadOneByte() throws Exception {
129         assertEquals('a', tee.read());
130         assertEquals("a", output.toString(ASCII));
131     }
132 
133     @Test
134     void testReadToArray() throws Exception {
135         final byte[] buffer = new byte[8];
136         assertEquals(3, tee.read(buffer));
137         assertEquals('a', buffer[0]);
138         assertEquals('b', buffer[1]);
139         assertEquals('c', buffer[2]);
140         assertEquals(-1, tee.read(buffer));
141         assertEquals("abc", output.toString(ASCII));
142     }
143 
144     @Test
145     void testReadToArrayWithOffset() throws Exception {
146         final byte[] buffer = new byte[8];
147         assertEquals(3, tee.read(buffer, 4, 4));
148         assertEquals('a', buffer[4]);
149         assertEquals('b', buffer[5]);
150         assertEquals('c', buffer[6]);
151         assertEquals(-1, tee.read(buffer, 4, 4));
152         assertEquals("abc", output.toString(ASCII));
153     }
154 
155     @Test
156     void testSkip() throws Exception {
157         assertEquals('a', tee.read());
158         assertEquals(1, tee.skip(1));
159         assertEquals('c', tee.read());
160         assertEquals(-1, tee.read());
161         assertEquals("ac", output.toString(ASCII));
162     }
163 
164 }