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.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  import static org.junit.jupiter.api.Assertions.fail;
24  
25  import java.io.EOFException;
26  import java.io.IOException;
27  import java.io.Reader;
28  
29  import org.junit.jupiter.api.Test;
30  
31  /**
32   * Tests {@link NullReader}.
33   */
34  public class NullReaderTest {
35  
36      private static final class TestNullReader extends NullReader {
37          public TestNullReader(final int size) {
38              super(size);
39          }
40  
41          public TestNullReader(final int size, final boolean markSupported, final boolean throwEofException) {
42              super(size, markSupported, throwEofException);
43          }
44  
45          @Override
46          protected int processChar() {
47              return (int) getPosition() - 1;
48          }
49  
50          @Override
51          protected void processChars(final char[] chars, final int offset, final int length) {
52              final int startPos = (int) getPosition() - length;
53              for (int i = offset; i < length; i++) {
54                  chars[i] = (char) (startPos + i);
55              }
56          }
57  
58      }
59  
60      // Use the same message as in java.io.InputStream.reset() in OpenJDK 8.0.275-1.
61      private static final String MARK_RESET_NOT_SUPPORTED = "mark/reset not supported";
62  
63      @Test
64      public void testEOFException() throws Exception {
65          try (Reader reader = new TestNullReader(2, false, true)) {
66              assertEquals(0, reader.read(), "Read 1");
67              assertEquals(1, reader.read(), "Read 2");
68              assertThrows(EOFException.class, () -> reader.read());
69          }
70      }
71  
72      @Test
73      public void testMarkAndReset() throws Exception {
74          int position = 0;
75          final int readLimit = 10;
76          try (Reader reader = new TestNullReader(100, true, false)) {
77  
78              assertTrue(reader.markSupported(), "Mark Should be Supported");
79  
80              // No Mark
81              final IOException resetException = assertThrows(IOException.class, reader::reset);
82              assertEquals("No position has been marked", resetException.getMessage(), "No Mark IOException message");
83  
84              for (; position < 3; position++) {
85                  assertEquals(position, reader.read(), "Read Before Mark [" + position + "]");
86              }
87  
88              // Mark
89              reader.mark(readLimit);
90  
91              // Read further
92              for (int i = 0; i < 3; i++) {
93                  assertEquals(position + i, reader.read(), "Read After Mark [" + i + "]");
94              }
95  
96              // Reset
97              reader.reset();
98  
99              // Read From marked position
100             for (int i = 0; i < readLimit + 1; i++) {
101                 assertEquals(position + i, reader.read(), "Read After Reset [" + i + "]");
102             }
103 
104             // Reset after read limit passed
105             final IOException e = assertThrows(IOException.class, reader::reset);
106             assertEquals("Marked position [" + position + "] is no longer valid - passed the read limit [" + readLimit + "]", e.getMessage(),
107                     "Read limit IOException message");
108         }
109     }
110 
111     @Test
112     public void testMarkNotSupported() throws Exception {
113         final Reader reader = new TestNullReader(100, false, true);
114         assertFalse(reader.markSupported(), "Mark Should NOT be Supported");
115 
116         try {
117             reader.mark(5);
118             fail("mark() should throw UnsupportedOperationException");
119         } catch (final UnsupportedOperationException e) {
120             assertEquals(MARK_RESET_NOT_SUPPORTED, e.getMessage(), "mark() error message");
121         }
122 
123         try {
124             reader.reset();
125             fail("reset() should throw UnsupportedOperationException");
126         } catch (final UnsupportedOperationException e) {
127             assertEquals(MARK_RESET_NOT_SUPPORTED, e.getMessage(), "reset() error message");
128         }
129         reader.close();
130     }
131 
132     @Test
133     public void testRead() throws Exception {
134         final int size = 5;
135         final TestNullReader reader = new TestNullReader(size);
136         for (int i = 0; i < size; i++) {
137             assertEquals(i, reader.read(), "Check Value [" + i + "]");
138         }
139 
140         // Check End of File
141         assertEquals(-1, reader.read(), "End of File");
142 
143         // Test reading after the end of file
144         try {
145             final int result = reader.read();
146             fail("Should have thrown an IOException, value=[" + result + "]");
147         } catch (final IOException e) {
148             assertEquals("Read after end of file", e.getMessage());
149         }
150 
151         // Close - should reset
152         reader.close();
153         assertEquals(0, reader.getPosition(), "Available after close");
154     }
155 
156     @Test
157     public void testReadCharArray() throws Exception {
158         final char[] chars = new char[10];
159         final Reader reader = new TestNullReader(15);
160 
161         // Read into array
162         final int count1 = reader.read(chars);
163         assertEquals(chars.length, count1, "Read 1");
164         for (int i = 0; i < count1; i++) {
165             assertEquals(i, chars[i], "Check Chars 1");
166         }
167 
168         // Read into array
169         final int count2 = reader.read(chars);
170         assertEquals(5, count2, "Read 2");
171         for (int i = 0; i < count2; i++) {
172             assertEquals(count1 + i, chars[i], "Check Chars 2");
173         }
174 
175         // End of File
176         final int count3 = reader.read(chars);
177         assertEquals(-1, count3, "Read 3 (EOF)");
178 
179         // Test reading after the end of file
180         try {
181             final int count4 = reader.read(chars);
182             fail("Should have thrown an IOException, value=[" + count4 + "]");
183         } catch (final IOException e) {
184             assertEquals("Read after end of file", e.getMessage());
185         }
186 
187         // reset by closing
188         reader.close();
189 
190         // Read into array using offset & length
191         final int offset = 2;
192         final int lth    = 4;
193         final int count5 = reader.read(chars, offset, lth);
194         assertEquals(lth, count5, "Read 5");
195         for (int i = offset; i < lth; i++) {
196             assertEquals(i, chars[i], "Check Chars 3");
197         }
198     }
199 
200     @Test
201     public void testSkip() throws Exception {
202         try (Reader reader = new TestNullReader(10, true, false)) {
203             assertEquals(0, reader.read(), "Read 1");
204             assertEquals(1, reader.read(), "Read 2");
205             assertEquals(5, reader.skip(5), "Skip 1");
206             assertEquals(7, reader.read(), "Read 3");
207             assertEquals(2, reader.skip(5), "Skip 2"); // only 2 left to skip
208             assertEquals(-1, reader.skip(5), "Skip 3 (EOF)"); // End of file
209 
210             final IOException e = assertThrows(IOException.class, () -> reader.skip(5));
211             assertEquals("Skip after end of file", e.getMessage(), "Skip after EOF IOException message");
212         }
213     }
214 }