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    *      http://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  public 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      public 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      /**
75       * Tests that the branch {@code OutputStream} is closed when closing the main {@code InputStream} throws an
76       * exception on {@link TeeInputStream#close()}, if specified to do so.
77       */
78      @Test
79      public void testCloseMainIOException() throws IOException {
80          final InputStream badIs = new ThrowOnCloseInputStream();
81          final ByteArrayOutputStream goodOs = mock(ByteArrayOutputStream.class);
82  
83          final TeeInputStream nonClosingTis = new TeeInputStream(badIs, goodOs, false);
84          assertThrows(IOException.class, nonClosingTis::close);
85          verify(goodOs, never()).close();
86  
87          final TeeInputStream closingTis = new TeeInputStream(badIs, goodOs, true);
88          assertThrows(IOException.class, closingTis::close);
89          verify(goodOs).close();
90      }
91  
92      @Test
93      public void testMarkReset() throws Exception {
94          assertEquals('a', tee.read());
95          tee.mark(1);
96          assertEquals('b', tee.read());
97          tee.reset();
98          assertEquals('b', tee.read());
99          assertEquals('c', tee.read());
100         assertEquals(-1, tee.read());
101         assertEquals("abbc", output.toString(ASCII));
102     }
103 
104     @Test
105     public void testReadEverything() throws Exception {
106         assertEquals('a', tee.read());
107         assertEquals('b', tee.read());
108         assertEquals('c', tee.read());
109         assertEquals(-1, tee.read());
110         assertEquals("abc", output.toString(ASCII));
111     }
112 
113     @Test
114     public void testReadNothing() throws Exception {
115         assertEquals("", output.toString(ASCII));
116     }
117 
118     @Test
119     public void testReadOneByte() throws Exception {
120         assertEquals('a', tee.read());
121         assertEquals("a", output.toString(ASCII));
122     }
123 
124     @Test
125     public void testReadToArray() throws Exception {
126         final byte[] buffer = new byte[8];
127         assertEquals(3, tee.read(buffer));
128         assertEquals('a', buffer[0]);
129         assertEquals('b', buffer[1]);
130         assertEquals('c', buffer[2]);
131         assertEquals(-1, tee.read(buffer));
132         assertEquals("abc", output.toString(ASCII));
133     }
134 
135     @Test
136     public void testReadToArrayWithOffset() throws Exception {
137         final byte[] buffer = new byte[8];
138         assertEquals(3, tee.read(buffer, 4, 4));
139         assertEquals('a', buffer[4]);
140         assertEquals('b', buffer[5]);
141         assertEquals('c', buffer[6]);
142         assertEquals(-1, tee.read(buffer, 4, 4));
143         assertEquals("abc", output.toString(ASCII));
144     }
145 
146     @Test
147     public void testSkip() throws Exception {
148         assertEquals('a', tee.read());
149         assertEquals(1, tee.skip(1));
150         assertEquals('c', tee.read());
151         assertEquals(-1, tee.read());
152         assertEquals("ac", output.toString(ASCII));
153     }
154 
155 }