View Javadoc
1   package org.codehaus.plexus.util;
2   
3   /*
4    * Copyright The Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.BufferedOutputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.io.PrintStream;
25  import java.io.PrintWriter;
26  import java.io.Reader;
27  import java.io.Writer;
28  import java.nio.file.Files;
29  
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  
33  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
34  import static org.junit.jupiter.api.Assertions.assertEquals;
35  import static org.junit.jupiter.api.Assertions.assertFalse;
36  import static org.junit.jupiter.api.Assertions.assertNotNull;
37  import static org.junit.jupiter.api.Assertions.assertTrue;
38  import static org.junit.jupiter.api.Assertions.fail;
39  
40  /**
41   * This is used to test IOUtil for correctness. The following checks are performed:
42   * <ul>
43   * <li>The return must not be null, must be the same type and equals() to the method's second arg</li>
44   * <li>All bytes must have been read from the source (available() == 0)</li>
45   * <li>The source and destination content must be identical (byte-wise comparison check)</li>
46   * <li>The output stream must not have been closed (a byte/char is written to test this, and subsequent size
47   * checked)</li>
48   * </ul>
49   * Due to interdependencies in IOUtils and IOUtilsTestlet, one bug may cause multiple tests to fail.
50   *
51   * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
52   * @since 3.4.0
53   */
54  @SuppressWarnings("deprecation")
55  public final class IOUtilTest {
56      /*
57       * Note: this is not particularly beautiful code. A better way to check for flush and close status would be to
58       * implement "trojan horse" wrapper implementations of the various stream classes, which set a flag when relevant
59       * methods are called. (JT)
60       */
61  
62      private final int FILE_SIZE = 1024 * 4 + 1;
63  
64      private File testDirectory;
65  
66      private File testFile;
67  
68      @BeforeEach
69      void setUp() {
70          try {
71              testDirectory = (new File("target/test/io/")).getAbsoluteFile();
72              if (!testDirectory.exists()) {
73                  testDirectory.mkdirs();
74              }
75  
76              testFile = new File(testDirectory, "file2-test.txt");
77  
78              createFile(testFile);
79          } catch (IOException ioe) {
80              throw new RuntimeException("Can't run this test because environment could not be built");
81          }
82      }
83  
84      public void tearDown() {
85          testFile.delete();
86          testDirectory.delete();
87      }
88  
89      private void createFile(File file) throws IOException {
90          BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()));
91  
92          for (int i = 0; i < FILE_SIZE; i++) {
93              output.write((byte) (i % 128)); // nice varied byte pattern compatible with Readers and Writers
94          }
95  
96          output.close();
97      }
98  
99      private void assertEqualContent(byte[] b0, byte[] b1) {
100         assertArrayEquals(b0, b1, "Content not equal according to java.util.Arrays#equals()");
101     }
102 
103     private void assertEqualContent(File f0, File f1) throws IOException {
104         byte[] buf0 = Files.readAllBytes(f0.toPath());
105         byte[] buf1 = Files.readAllBytes(f1.toPath());
106         assertArrayEquals(buf0, buf1, "The files " + f0 + " and " + f1 + " have different content");
107     }
108 
109     private void assertEqualContent(byte[] b0, File file) throws IOException {
110         byte[] b1 = Files.readAllBytes(file.toPath());
111         assertArrayEquals(b0, b1, "Content differs");
112     }
113 
114     @Test
115     void inputStreamToOutputStream() throws Exception {
116         File destination = newFile("copy1.txt");
117         try (InputStream fin = Files.newInputStream(testFile.toPath());
118                 OutputStream fout = Files.newOutputStream(destination.toPath())) {
119 
120             IOUtil.copy(fin, fout);
121 
122             assertEquals(0, fin.available(), "Not all bytes were read");
123             fout.flush();
124 
125             checkFile(destination);
126             checkWrite(fout);
127         }
128         deleteFile(destination);
129     }
130 
131     @Test
132     void inputStreamToWriter() throws Exception {
133         File destination = newFile("copy2.txt");
134         InputStream fin = Files.newInputStream(testFile.toPath());
135         Writer fout = Files.newBufferedWriter(destination.toPath());
136 
137         IOUtil.copy(fin, fout);
138 
139         assertEquals(0, fin.available(), "Not all bytes were read");
140         fout.flush();
141 
142         checkFile(destination);
143         checkWrite(fout);
144         fout.close();
145         fin.close();
146         deleteFile(destination);
147     }
148 
149     @Test
150     void inputStreamToString() throws Exception {
151         InputStream fin = Files.newInputStream(testFile.toPath());
152         String out = IOUtil.toString(fin);
153         assertNotNull(out);
154         assertEquals(0, fin.available(), "Not all bytes were read");
155         assertEquals(out.length(), FILE_SIZE, "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE);
156         fin.close();
157     }
158 
159     @Test
160     void readerToOutputStream() throws Exception {
161         File destination = newFile("copy3.txt");
162         Reader fin = Files.newBufferedReader(testFile.toPath());
163         OutputStream fout = Files.newOutputStream(destination.toPath());
164         IOUtil.copy(fin, fout);
165         // Note: this method *does* flush. It is equivalent to:
166         // OutputStreamWriter _out = new OutputStreamWriter(fout);
167         // IOUtil.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
168         // _out.flush();
169         // out = fout;
170 
171         // Note: rely on the method to flush
172         checkFile(destination);
173         checkWrite(fout);
174         fout.close();
175         fin.close();
176         deleteFile(destination);
177     }
178 
179     @Test
180     void readerToWriter() throws Exception {
181         File destination = newFile("copy4.txt");
182         Reader fin = Files.newBufferedReader(testFile.toPath());
183         Writer fout = Files.newBufferedWriter(destination.toPath());
184         IOUtil.copy(fin, fout);
185 
186         fout.flush();
187         checkFile(destination);
188         checkWrite(fout);
189         fout.close();
190         fin.close();
191         deleteFile(destination);
192     }
193 
194     @Test
195     void readerToString() throws Exception {
196         Reader fin = Files.newBufferedReader(testFile.toPath());
197         String out = IOUtil.toString(fin);
198         assertNotNull(out);
199         assertEquals(out.length(), FILE_SIZE, "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE);
200         fin.close();
201     }
202 
203     @Test
204     void stringToOutputStream() throws Exception {
205         File destination = newFile("copy5.txt");
206         Reader fin = Files.newBufferedReader(testFile.toPath());
207         // Create our String. Rely on testReaderToString() to make sure this is valid.
208         String str = IOUtil.toString(fin);
209         OutputStream fout = Files.newOutputStream(destination.toPath());
210         IOUtil.copy(str, fout);
211         // Note: this method *does* flush. It is equivalent to:
212         // OutputStreamWriter _out = new OutputStreamWriter(fout);
213         // IOUtil.copy( str, _out, 4096 ); // copy( Reader, Writer, int );
214         // _out.flush();
215         // out = fout;
216         // note: we don't flush here; this IOUtils method does it for us
217 
218         checkFile(destination);
219         checkWrite(fout);
220         fout.close();
221         fin.close();
222         deleteFile(destination);
223     }
224 
225     @Test
226     void stringToWriter() throws Exception {
227         File destination = newFile("copy6.txt");
228         Reader fin = Files.newBufferedReader(testFile.toPath());
229         // Create our String. Rely on testReaderToString() to make sure this is valid.
230         String str = IOUtil.toString(fin);
231         Writer fout = Files.newBufferedWriter(destination.toPath());
232         IOUtil.copy(str, fout);
233         fout.flush();
234 
235         checkFile(destination);
236         checkWrite(fout);
237         fout.close();
238         fin.close();
239 
240         deleteFile(destination);
241     }
242 
243     @Test
244     void inputStreamToByteArray() throws Exception {
245         InputStream fin = Files.newInputStream(testFile.toPath());
246         byte[] out = IOUtil.toByteArray(fin);
247         assertNotNull(out);
248         assertEquals(0, fin.available(), "Not all bytes were read");
249         assertEquals(out.length, FILE_SIZE, "Wrong output size: out.length=" + out.length + "!=" + FILE_SIZE);
250         assertEqualContent(out, testFile);
251         fin.close();
252     }
253 
254     @Test
255     void stringToByteArray() throws Exception {
256         Reader fin = Files.newBufferedReader(testFile.toPath());
257 
258         // Create our String. Rely on testReaderToString() to make sure this is valid.
259         String str = IOUtil.toString(fin);
260 
261         byte[] out = IOUtil.toByteArray(str);
262         assertEqualContent(str.getBytes(), out);
263         fin.close();
264     }
265 
266     @Test
267     void byteArrayToWriter() throws Exception {
268         File destination = newFile("copy7.txt");
269         Writer fout = Files.newBufferedWriter(destination.toPath());
270         InputStream fin = Files.newInputStream(testFile.toPath());
271 
272         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
273         byte[] in = IOUtil.toByteArray(fin);
274         IOUtil.copy(in, fout);
275         fout.flush();
276         checkFile(destination);
277         checkWrite(fout);
278         fout.close();
279         fin.close();
280         deleteFile(destination);
281     }
282 
283     @Test
284     void byteArrayToString() throws Exception {
285         InputStream fin = Files.newInputStream(testFile.toPath());
286         byte[] in = IOUtil.toByteArray(fin);
287         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
288         String str = IOUtil.toString(in);
289         assertEqualContent(in, str.getBytes());
290         fin.close();
291     }
292 
293     @Test
294     void byteArrayToOutputStream() throws Exception {
295         File destination = newFile("copy8.txt");
296         OutputStream fout = Files.newOutputStream(destination.toPath());
297         InputStream fin = Files.newInputStream(testFile.toPath());
298 
299         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
300         byte[] in = IOUtil.toByteArray(fin);
301 
302         IOUtil.copy(in, fout);
303 
304         fout.flush();
305 
306         checkFile(destination);
307         checkWrite(fout);
308         fout.close();
309         fin.close();
310         deleteFile(destination);
311     }
312 
313     @Test
314     void closeInputStream() {
315         IOUtil.close((InputStream) null);
316 
317         TestInputStream inputStream = new TestInputStream();
318 
319         IOUtil.close(inputStream);
320 
321         assertTrue(inputStream.closed);
322     }
323 
324     @Test
325     void closeOutputStream() throws Exception {
326         IOUtil.close((OutputStream) null);
327 
328         TestOutputStream outputStream = new TestOutputStream();
329 
330         IOUtil.close(outputStream);
331 
332         assertTrue(outputStream.closed);
333     }
334 
335     @Test
336     void closeReader() throws Exception {
337         IOUtil.close((Reader) null);
338 
339         TestReader reader = new TestReader();
340 
341         IOUtil.close(reader);
342 
343         assertTrue(reader.closed);
344     }
345 
346     @Test
347     void closeWriter() throws Exception {
348         IOUtil.close((Writer) null);
349 
350         TestWriter writer = new TestWriter();
351 
352         IOUtil.close(writer);
353 
354         assertTrue(writer.closed);
355     }
356 
357     private static class TestInputStream extends InputStream {
358         boolean closed;
359 
360         public void close() {
361             closed = true;
362         }
363 
364         public int read() {
365             fail("This method shouldn't be called");
366 
367             return 0;
368         }
369     }
370 
371     private static class TestOutputStream extends OutputStream {
372         boolean closed;
373 
374         public void close() {
375             closed = true;
376         }
377 
378         public void write(int value) {
379             fail("This method shouldn't be called");
380         }
381     }
382 
383     private static class TestReader extends Reader {
384         boolean closed;
385 
386         public void close() {
387             closed = true;
388         }
389 
390         public int read(char[] cbuf, int off, int len) {
391             fail("This method shouldn't be called");
392 
393             return 0;
394         }
395     }
396 
397     private static class TestWriter extends Writer {
398         boolean closed;
399 
400         public void close() {
401             closed = true;
402         }
403 
404         public void write(char[] cbuf, int off, int len) {
405             fail("This method shouldn't be called");
406         }
407 
408         public void flush() {
409             fail("This method shouldn't be called");
410         }
411     }
412 
413     private File newFile(String filename) throws Exception {
414         File destination = new File(testDirectory, filename);
415         assertFalse(destination.exists(), filename + "Test output data file shouldn't previously exist");
416 
417         return destination;
418     }
419 
420     private void checkFile(File file) throws Exception {
421         assertTrue(file.exists(), "Check existence of output file");
422         assertEqualContent(testFile, file);
423     }
424 
425     private void checkWrite(OutputStream output) throws Exception {
426         try {
427             new PrintStream(output).write(0);
428         } catch (Throwable t) {
429             throw new Exception("The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage());
430         }
431     }
432 
433     private void checkWrite(Writer output) throws Exception {
434         try {
435             new PrintWriter(output).write('a');
436         } catch (Throwable t) {
437             throw new Exception("The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage());
438         }
439     }
440 
441     private void deleteFile(File file) throws Exception {
442         assertEquals(
443                 file.length(),
444                 FILE_SIZE + 1,
445                 "Wrong output size: file.length()=" + file.length() + "!=" + FILE_SIZE + 1);
446 
447         assertTrue((file.delete() || (!file.exists())), "File would not delete");
448     }
449 }