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  import java.util.Arrays;
30  
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  
34  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
35  import static org.junit.jupiter.api.Assertions.assertNotNull;
36  import static org.junit.jupiter.api.Assertions.assertTrue;
37  import static org.junit.jupiter.api.Assertions.fail;
38  
39  /**
40   * This is used to test IOUtil for correctness. The following checks are performed:
41   * <ul>
42   * <li>The return must not be null, must be the same type and equals() to the method's second arg</li>
43   * <li>All bytes must have been read from the source (available() == 0)</li>
44   * <li>The source and destination content must be identical (byte-wise comparison check)</li>
45   * <li>The output stream must not have been closed (a byte/char is written to test this, and subsequent size
46   * checked)</li>
47   * </ul>
48   * Due to interdependencies in IOUtils and IOUtilsTestlet, one bug may cause multiple tests to fail.
49   *
50   * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
51   * @version $Id: $Id
52   * @since 3.4.0
53   */
54  public final class IOUtilTest {
55      /*
56       * Note: this is not particularly beautiful code. A better way to check for flush and close status would be to
57       * implement "trojan horse" wrapper implementations of the various stream classes, which set a flag when relevant
58       * methods are called. (JT)
59       */
60  
61      private int FILE_SIZE = 1024 * 4 + 1;
62  
63      private File testDirectory;
64  
65      private File testFile;
66  
67      /**
68       * <p>setUp.</p>
69       */
70      @BeforeEach
71      public void setUp() {
72          try {
73              testDirectory = (new File("target/test/io/")).getAbsoluteFile();
74              if (!testDirectory.exists()) {
75                  testDirectory.mkdirs();
76              }
77  
78              testFile = new File(testDirectory, "file2-test.txt");
79  
80              createFile(testFile, FILE_SIZE);
81          } catch (IOException ioe) {
82              throw new RuntimeException("Can't run this test because environment could not be built");
83          }
84      }
85  
86      /**
87       * <p>tearDown.</p>
88       */
89      public void tearDown() {
90          testFile.delete();
91          testDirectory.delete();
92      }
93  
94      private void createFile(File file, long size) throws IOException {
95          BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()));
96  
97          for (int i = 0; i < size; i++) {
98              output.write((byte) (i % 128)); // nice varied byte pattern compatible with Readers and Writers
99          }
100 
101         output.close();
102     }
103 
104     /** Assert that the contents of two byte arrays are the same. */
105     private void assertEqualContent(byte[] b0, byte[] b1) {
106         assertTrue(Arrays.equals(b0, b1), "Content not equal according to java.util.Arrays#equals()");
107     }
108 
109     /** Assert that the content of two files is the same. */
110     private void assertEqualContent(File f0, File f1) throws IOException {
111         byte[] buf0 = Files.readAllBytes(f0.toPath());
112         byte[] buf1 = Files.readAllBytes(f1.toPath());
113         assertArrayEquals(buf0, buf1, "The files " + f0 + " and " + f1 + " have different content");
114     }
115 
116     /** Assert that the content of a file is equal to that in a byte[]. */
117     private void assertEqualContent(byte[] b0, File file) throws IOException {
118         byte[] b1 = Files.readAllBytes(file.toPath());
119         assertArrayEquals(b0, b1, "Content differs");
120     }
121 
122     /**
123      * <p>testInputStreamToOutputStream.</p>
124      *
125      * @throws java.lang.Exception if any.
126      */
127     @Test
128     public void testInputStreamToOutputStream() throws Exception {
129         File destination = newFile("copy1.txt");
130         InputStream fin = Files.newInputStream(testFile.toPath());
131         OutputStream fout = Files.newOutputStream(destination.toPath());
132 
133         IOUtil.copy(fin, fout);
134         assertTrue(fin.available() == 0, "Not all bytes were read");
135         fout.flush();
136 
137         checkFile(destination);
138         checkWrite(fout);
139         fout.close();
140         fin.close();
141         deleteFile(destination);
142     }
143 
144     /**
145      * <p>testInputStreamToWriter.</p>
146      *
147      * @throws java.lang.Exception if any.
148      */
149     @org.junit.jupiter.api.Test
150     public void testInputStreamToWriter() throws Exception {
151         File destination = newFile("copy2.txt");
152         InputStream fin = Files.newInputStream(testFile.toPath());
153         Writer fout = Files.newBufferedWriter(destination.toPath());
154 
155         IOUtil.copy(fin, fout);
156 
157         assertTrue(fin.available() == 0, "Not all bytes were read");
158         fout.flush();
159 
160         checkFile(destination);
161         checkWrite(fout);
162         fout.close();
163         fin.close();
164         deleteFile(destination);
165     }
166 
167     /**
168      * <p>testInputStreamToString.</p>
169      *
170      * @throws java.lang.Exception if any.
171      */
172     @Test
173     public void testInputStreamToString() throws Exception {
174         InputStream fin = Files.newInputStream(testFile.toPath());
175         String out = IOUtil.toString(fin);
176         assertNotNull(out);
177         assertTrue(fin.available() == 0, "Not all bytes were read");
178         assertTrue(out.length() == FILE_SIZE, "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE);
179         fin.close();
180     }
181 
182     /**
183      * <p>testReaderToOutputStream.</p>
184      *
185      * @throws java.lang.Exception if any.
186      */
187     @Test
188     public void testReaderToOutputStream() throws Exception {
189         File destination = newFile("copy3.txt");
190         Reader fin = Files.newBufferedReader(testFile.toPath());
191         OutputStream fout = Files.newOutputStream(destination.toPath());
192         IOUtil.copy(fin, fout);
193         // Note: this method *does* flush. It is equivalent to:
194         // OutputStreamWriter _out = new OutputStreamWriter(fout);
195         // IOUtil.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
196         // _out.flush();
197         // out = fout;
198 
199         // Note: rely on the method to flush
200         checkFile(destination);
201         checkWrite(fout);
202         fout.close();
203         fin.close();
204         deleteFile(destination);
205     }
206 
207     /**
208      * <p>testReaderToWriter.</p>
209      *
210      * @throws java.lang.Exception if any.
211      */
212     @org.junit.jupiter.api.Test
213     public void testReaderToWriter() throws Exception {
214         File destination = newFile("copy4.txt");
215         Reader fin = Files.newBufferedReader(testFile.toPath());
216         Writer fout = Files.newBufferedWriter(destination.toPath());
217         IOUtil.copy(fin, fout);
218 
219         fout.flush();
220         checkFile(destination);
221         checkWrite(fout);
222         fout.close();
223         fin.close();
224         deleteFile(destination);
225     }
226 
227     /**
228      * <p>testReaderToString.</p>
229      *
230      * @throws java.lang.Exception if any.
231      */
232     @org.junit.jupiter.api.Test
233     public void testReaderToString() throws Exception {
234         Reader fin = Files.newBufferedReader(testFile.toPath());
235         String out = IOUtil.toString(fin);
236         assertNotNull(out);
237         assertTrue(out.length() == FILE_SIZE, "Wrong output size: out.length()=" + out.length() + "!=" + FILE_SIZE);
238         fin.close();
239     }
240 
241     /**
242      * <p>testStringToOutputStream.</p>
243      *
244      * @throws java.lang.Exception if any.
245      */
246     @org.junit.jupiter.api.Test
247     public void testStringToOutputStream() throws Exception {
248         File destination = newFile("copy5.txt");
249         Reader fin = Files.newBufferedReader(testFile.toPath());
250         // Create our String. Rely on testReaderToString() to make sure this is valid.
251         String str = IOUtil.toString(fin);
252         OutputStream fout = Files.newOutputStream(destination.toPath());
253         IOUtil.copy(str, fout);
254         // Note: this method *does* flush. It is equivalent to:
255         // OutputStreamWriter _out = new OutputStreamWriter(fout);
256         // IOUtil.copy( str, _out, 4096 ); // copy( Reader, Writer, int );
257         // _out.flush();
258         // out = fout;
259         // note: we don't flush here; this IOUtils method does it for us
260 
261         checkFile(destination);
262         checkWrite(fout);
263         fout.close();
264         fin.close();
265         deleteFile(destination);
266     }
267 
268     /**
269      * <p>testStringToWriter.</p>
270      *
271      * @throws java.lang.Exception if any.
272      */
273     @org.junit.jupiter.api.Test
274     public void testStringToWriter() throws Exception {
275         File destination = newFile("copy6.txt");
276         Reader fin = Files.newBufferedReader(testFile.toPath());
277         // Create our String. Rely on testReaderToString() to make sure this is valid.
278         String str = IOUtil.toString(fin);
279         Writer fout = Files.newBufferedWriter(destination.toPath());
280         IOUtil.copy(str, fout);
281         fout.flush();
282 
283         checkFile(destination);
284         checkWrite(fout);
285         fout.close();
286         fin.close();
287 
288         deleteFile(destination);
289     }
290 
291     /**
292      * <p>testInputStreamToByteArray.</p>
293      *
294      * @throws java.lang.Exception if any.
295      */
296     @Test
297     public void testInputStreamToByteArray() throws Exception {
298         InputStream fin = Files.newInputStream(testFile.toPath());
299         byte[] out = IOUtil.toByteArray(fin);
300         assertNotNull(out);
301         assertTrue(fin.available() == 0, "Not all bytes were read");
302         assertTrue(out.length == FILE_SIZE, "Wrong output size: out.length=" + out.length + "!=" + FILE_SIZE);
303         assertEqualContent(out, testFile);
304         fin.close();
305     }
306 
307     /**
308      * <p>testStringToByteArray.</p>
309      *
310      * @throws java.lang.Exception if any.
311      */
312     @Test
313     public void testStringToByteArray() throws Exception {
314         Reader fin = Files.newBufferedReader(testFile.toPath());
315 
316         // Create our String. Rely on testReaderToString() to make sure this is valid.
317         String str = IOUtil.toString(fin);
318 
319         byte[] out = IOUtil.toByteArray(str);
320         assertEqualContent(str.getBytes(), out);
321         fin.close();
322     }
323 
324     /**
325      * <p>testByteArrayToWriter.</p>
326      *
327      * @throws java.lang.Exception if any.
328      */
329     @Test
330     public void testByteArrayToWriter() throws Exception {
331         File destination = newFile("copy7.txt");
332         Writer fout = Files.newBufferedWriter(destination.toPath());
333         InputStream fin = Files.newInputStream(testFile.toPath());
334 
335         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
336         byte[] in = IOUtil.toByteArray(fin);
337         IOUtil.copy(in, fout);
338         fout.flush();
339         checkFile(destination);
340         checkWrite(fout);
341         fout.close();
342         fin.close();
343         deleteFile(destination);
344     }
345 
346     /**
347      * <p>testByteArrayToString.</p>
348      *
349      * @throws java.lang.Exception if any.
350      */
351     @org.junit.jupiter.api.Test
352     public void testByteArrayToString() throws Exception {
353         InputStream fin = Files.newInputStream(testFile.toPath());
354         byte[] in = IOUtil.toByteArray(fin);
355         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
356         String str = IOUtil.toString(in);
357         assertEqualContent(in, str.getBytes());
358         fin.close();
359     }
360 
361     /**
362      * <p>testByteArrayToOutputStream.</p>
363      *
364      * @throws java.lang.Exception if any.
365      */
366     @Test
367     public void testByteArrayToOutputStream() throws Exception {
368         File destination = newFile("copy8.txt");
369         OutputStream fout = Files.newOutputStream(destination.toPath());
370         InputStream fin = Files.newInputStream(testFile.toPath());
371 
372         // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
373         byte[] in = IOUtil.toByteArray(fin);
374 
375         IOUtil.copy(in, fout);
376 
377         fout.flush();
378 
379         checkFile(destination);
380         checkWrite(fout);
381         fout.close();
382         fin.close();
383         deleteFile(destination);
384     }
385 
386     // ----------------------------------------------------------------------
387     // Test closeXXX()
388     // ----------------------------------------------------------------------
389 
390     /**
391      * <p>testCloseInputStream.</p>
392      *
393      * @throws java.lang.Exception if any.
394      */
395     @org.junit.jupiter.api.Test
396     public void testCloseInputStream() throws Exception {
397         IOUtil.close((InputStream) null);
398 
399         TestInputStream inputStream = new TestInputStream();
400 
401         IOUtil.close(inputStream);
402 
403         assertTrue(inputStream.closed);
404     }
405 
406     /**
407      * <p>testCloseOutputStream.</p>
408      *
409      * @throws java.lang.Exception if any.
410      */
411     @org.junit.jupiter.api.Test
412     public void testCloseOutputStream() throws Exception {
413         IOUtil.close((OutputStream) null);
414 
415         TestOutputStream outputStream = new TestOutputStream();
416 
417         IOUtil.close(outputStream);
418 
419         assertTrue(outputStream.closed);
420     }
421 
422     /**
423      * <p>testCloseReader.</p>
424      *
425      * @throws java.lang.Exception if any.
426      */
427     @Test
428     public void testCloseReader() throws Exception {
429         IOUtil.close((Reader) null);
430 
431         TestReader reader = new TestReader();
432 
433         IOUtil.close(reader);
434 
435         assertTrue(reader.closed);
436     }
437 
438     /**
439      * <p>testCloseWriter.</p>
440      *
441      * @throws java.lang.Exception if any.
442      */
443     @Test
444     public void testCloseWriter() throws Exception {
445         IOUtil.close((Writer) null);
446 
447         TestWriter writer = new TestWriter();
448 
449         IOUtil.close(writer);
450 
451         assertTrue(writer.closed);
452     }
453 
454     private class TestInputStream extends InputStream {
455         boolean closed;
456 
457         public void close() {
458             closed = true;
459         }
460 
461         public int read() {
462             fail("This method shouldn't be called");
463 
464             return 0;
465         }
466     }
467 
468     private class TestOutputStream extends OutputStream {
469         boolean closed;
470 
471         public void close() {
472             closed = true;
473         }
474 
475         public void write(int value) {
476             fail("This method shouldn't be called");
477         }
478     }
479 
480     private class TestReader extends Reader {
481         boolean closed;
482 
483         public void close() {
484             closed = true;
485         }
486 
487         public int read(char cbuf[], int off, int len) {
488             fail("This method shouldn't be called");
489 
490             return 0;
491         }
492     }
493 
494     private class TestWriter extends Writer {
495         boolean closed;
496 
497         public void close() {
498             closed = true;
499         }
500 
501         public void write(char cbuf[], int off, int len) {
502             fail("This method shouldn't be called");
503         }
504 
505         public void flush() {
506             fail("This method shouldn't be called");
507         }
508     }
509 
510     // ----------------------------------------------------------------------
511     // Utility methods
512     // ----------------------------------------------------------------------
513 
514     private File newFile(String filename) throws Exception {
515         File destination = new File(testDirectory, filename);
516         assertTrue(!destination.exists(), filename + "Test output data file shouldn't previously exist");
517 
518         return destination;
519     }
520 
521     private void checkFile(File file) throws Exception {
522         assertTrue(file.exists(), "Check existence of output file");
523         assertEqualContent(testFile, file);
524     }
525 
526     private void checkWrite(OutputStream output) throws Exception {
527         try {
528             new PrintStream(output).write(0);
529         } catch (Throwable t) {
530             throw new Exception("The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage());
531         }
532     }
533 
534     private void checkWrite(Writer output) throws Exception {
535         try {
536             new PrintWriter(output).write('a');
537         } catch (Throwable t) {
538             throw new Exception("The copy() method closed the stream " + "when it shouldn't have. " + t.getMessage());
539         }
540     }
541 
542     private void deleteFile(File file) throws Exception {
543         assertTrue(
544                 file.length() == FILE_SIZE + 1,
545                 "Wrong output size: file.length()=" + file.length() + "!=" + FILE_SIZE + 1);
546 
547         assertTrue((file.delete() || (!file.exists())), "File would not delete");
548     }
549 }