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