Testcases for new classes from Avalon excalibur.


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/io/trunk@140305 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/test/org/apache/commons/io/DemuxTestCase.java b/src/test/org/apache/commons/io/DemuxTestCase.java
new file mode 100644
index 0000000..ffdec57
--- /dev/null
+++ b/src/test/org/apache/commons/io/DemuxTestCase.java
@@ -0,0 +1,286 @@
+/*
+ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//io/src/test/org/apache/commons/io/DemuxTestCase.java,v 1.1 2002/07/08 22:19:10 nicolaken Exp $
+ * $Revision: 1.1 $
+ * $Date: 2002/07/08 22:19:10 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Random;
+import junit.framework.TestCase;
+import org.apache.avalon.excalibur.io.DemuxInputStream;
+import org.apache.avalon.excalibur.io.DemuxOutputStream;
+
+/**
+ * Basic unit tests for the multiplexing streams.
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ */
+public final class DemuxTestCase
+    extends TestCase
+{
+    private static final String T1 = "Thread1";
+    private static final String T2 = "Thread2";
+    private static final String T3 = "Thread3";
+    private static final String T4 = "Thread4";
+
+    private static final String DATA1 = "Data for thread1";
+    private static final String DATA2 = "Data for thread2";
+    private static final String DATA3 = "Data for thread3";
+    private static final String DATA4 = "Data for thread4";
+
+    private static final Random c_random = new Random();
+    private final HashMap m_outputMap = new HashMap();
+    private final HashMap m_threadMap = new HashMap();
+
+    public DemuxTestCase( final String name )
+    {
+        super( name );
+    }
+
+    private String getOutput( final String threadName )
+        throws IOException
+    {
+        final ByteArrayOutputStream output =
+            (ByteArrayOutputStream)m_outputMap.get( threadName );
+        assertNotNull( "getOutput()", output );
+
+        return output.toString();
+    }
+
+    private String getInput( final String threadName )
+        throws IOException
+    {
+        final ReaderThread thread = (ReaderThread)m_threadMap.get( threadName );
+        assertNotNull( "getInput()", thread );
+
+        return thread.getData();
+    }
+
+    private void doStart()
+        throws Exception
+    {
+        final Iterator iterator = m_threadMap.keySet().iterator();
+        while( iterator.hasNext() )
+        {
+            final String name = (String)iterator.next();
+            final Thread thread = (Thread)m_threadMap.get( name );
+            thread.start();
+        }
+    }
+
+    private void doJoin()
+        throws Exception
+    {
+        final Iterator iterator = m_threadMap.keySet().iterator();
+        while( iterator.hasNext() )
+        {
+            final String name = (String)iterator.next();
+            final Thread thread = (Thread)m_threadMap.get( name );
+            thread.join();
+        }
+    }
+
+    private void startWriter( final String name,
+                              final String data,
+                              final DemuxOutputStream demux )
+        throws Exception
+    {
+        final ByteArrayOutputStream output = new ByteArrayOutputStream();
+        m_outputMap.put( name, output );
+        final WriterThread thread =
+            new WriterThread( name, data, output, demux );
+        m_threadMap.put( name, thread );
+    }
+
+    private void startReader( final String name,
+                              final String data,
+                              final DemuxInputStream demux )
+        throws Exception
+    {
+        final ByteArrayInputStream input = new ByteArrayInputStream( data.getBytes() );
+        final ReaderThread thread = new ReaderThread( name, input, demux );
+        m_threadMap.put( name, thread );
+    }
+
+    public void testOutputStream()
+        throws Exception
+    {
+        final DemuxOutputStream output = new DemuxOutputStream();
+        startWriter( T1, DATA1, output );
+        startWriter( T2, DATA2, output );
+        startWriter( T3, DATA3, output );
+        startWriter( T4, DATA4, output );
+
+        doStart();
+        doJoin();
+
+        assertEquals( "Data1", DATA1, getOutput( T1 ) );
+        assertEquals( "Data2", DATA2, getOutput( T2 ) );
+        assertEquals( "Data3", DATA3, getOutput( T3 ) );
+        assertEquals( "Data4", DATA4, getOutput( T4 ) );
+    }
+
+    public void testInputStream()
+        throws Exception
+    {
+        final DemuxInputStream input = new DemuxInputStream();
+        startReader( T1, DATA1, input );
+        startReader( T2, DATA2, input );
+        startReader( T3, DATA3, input );
+        startReader( T4, DATA4, input );
+
+        doStart();
+        doJoin();
+
+        assertEquals( "Data1", DATA1, getInput( T1 ) );
+        assertEquals( "Data2", DATA2, getInput( T2 ) );
+        assertEquals( "Data3", DATA3, getInput( T3 ) );
+        assertEquals( "Data4", DATA4, getInput( T4 ) );
+    }
+
+    private static class ReaderThread
+        extends Thread
+    {
+        private final StringBuffer m_buffer = new StringBuffer();
+        private final InputStream m_input;
+        private final DemuxInputStream m_demux;
+
+        ReaderThread( final String name,
+                      final InputStream input,
+                      final DemuxInputStream demux )
+        {
+            super( name );
+            m_input = input;
+            m_demux = demux;
+        }
+
+        public String getData()
+        {
+            return m_buffer.toString();
+        }
+
+        public void run()
+        {
+            m_demux.bindStream( m_input );
+
+            try
+            {
+                int ch = m_demux.read();
+                while( -1 != ch )
+                {
+                    //System.out.println( "Reading: " + (char)ch );
+                    m_buffer.append( (char)ch );
+
+                    final int sleepTime = Math.abs( c_random.nextInt() % 10 );
+                    Thread.sleep( sleepTime );
+                    ch = m_demux.read();
+                }
+            }
+            catch( final Exception e )
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static class WriterThread
+        extends Thread
+    {
+        private final byte[] m_data;
+        private final OutputStream m_output;
+        private final DemuxOutputStream m_demux;
+
+        WriterThread( final String name,
+                      final String data,
+                      final OutputStream output,
+                      final DemuxOutputStream demux )
+        {
+            super( name );
+            m_output = output;
+            m_demux = demux;
+            m_data = data.getBytes();
+        }
+
+        public void run()
+        {
+            m_demux.bindStream( m_output );
+            for( int i = 0; i < m_data.length; i++ )
+            {
+                try
+                {
+                    //System.out.println( "Writing: " + (char)m_data[ i ] );
+                    m_demux.write( m_data[ i ] );
+                    final int sleepTime = Math.abs( c_random.nextInt() % 10 );
+                    Thread.sleep( sleepTime );
+                }
+                catch( final Exception e )
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/FileUtilTestCase.java b/src/test/org/apache/commons/io/FileUtilTestCase.java
new file mode 100644
index 0000000..273f6ab
--- /dev/null
+++ b/src/test/org/apache/commons/io/FileUtilTestCase.java
@@ -0,0 +1,243 @@
+/*
+ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//io/src/test/org/apache/commons/io/Attic/FileUtilTestCase.java,v 1.1 2002/07/08 22:19:10 nicolaken Exp $
+ * $Revision: 1.1 $
+ * $Date: 2002/07/08 22:19:10 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.io;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.avalon.excalibur.io.FileUtil;
+
+/**
+ * This is used to test FileUtil for correctness.
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ */
+public final class FileUtilTestCase
+    extends TestCase
+{
+    private final int FILE1_SIZE = 1;
+    private final int FILE2_SIZE = 1024 * 4 + 1;
+
+    private final File m_testDirectory;
+    private final File m_testFile1;
+    private final File m_testFile2;
+
+    public FileUtilTestCase( final String name )
+        throws IOException
+    {
+        super( name );
+
+        m_testDirectory = ( new File( "test/io/" ) ).getAbsoluteFile();
+        if( !m_testDirectory.exists() )
+        {
+            m_testDirectory.mkdirs();
+        }
+
+        m_testFile1 = new File( m_testDirectory, "file1-test.txt" );
+        m_testFile2 = new File( m_testDirectory, "file2-test.txt" );
+
+        createFile( m_testFile1, FILE1_SIZE );
+        createFile( m_testFile2, FILE2_SIZE );
+    }
+
+    private void createFile( final File file, final long size )
+        throws IOException
+    {
+        final BufferedOutputStream output =
+            new BufferedOutputStream( new FileOutputStream( file ) );
+
+        for( int i = 0; i < size; i++ )
+        {
+            output.write( (byte)'X' );
+        }
+
+        output.close();
+    }
+
+    public static Test suite()
+        throws IOException
+    {
+        final TestSuite suite = new TestSuite();
+        suite.addTest( new FileUtilTestCase( "testCopyFile1" ) );
+        suite.addTest( new FileUtilTestCase( "testCopyFile2" ) );
+        suite.addTest( new FileUtilTestCase( "testForceDeleteAFile1" ) );
+        suite.addTest( new FileUtilTestCase( "testForceDeleteAFile2" ) );
+        suite.addTest( new FileUtilTestCase( "testCopyFile1ToDir" ) );
+        suite.addTest( new FileUtilTestCase( "testCopyFile2ToDir" ) );
+        suite.addTest( new FileUtilTestCase( "testForceDeleteDir" ) );
+        suite.addTest( new FileUtilTestCase( "testResolveFileDotDot" ) );
+        suite.addTest( new FileUtilTestCase( "testResolveFileDot" ) );
+        suite.addTest( new FileUtilTestCase( "testNormalize" ) );
+        return suite;
+    }
+
+    public void testCopyFile1()
+        throws Exception
+    {
+        final File destination = new File( m_testDirectory, "copy1.txt" );
+        FileUtil.copyFile( m_testFile1, destination );
+        assertTrue( "Check Exist", destination.exists() );
+        assertTrue( "Check Full copy", destination.length() == FILE1_SIZE );
+    }
+
+    public void testCopyFile2()
+        throws Exception
+    {
+        final File destination = new File( m_testDirectory, "copy2.txt" );
+        FileUtil.copyFile( m_testFile2, destination );
+        assertTrue( "Check Exist", destination.exists() );
+        assertTrue( "Check Full copy", destination.length() == FILE2_SIZE );
+    }
+
+    public void testForceDeleteAFile1()
+        throws Exception
+    {
+        final File destination = new File( m_testDirectory, "copy1.txt" );
+        destination.createNewFile();
+        assertTrue( "Copy1.txt doesn't exist to delete", destination.exists() );
+        FileUtil.forceDelete( destination );
+        assertTrue( "Check No Exist", !destination.exists() );
+    }
+
+    public void testForceDeleteAFile2()
+        throws Exception
+    {
+        final File destination = new File( m_testDirectory, "copy2.txt" );
+        destination.createNewFile();
+        assertTrue( "Copy2.txt doesn't exist to delete", destination.exists() );
+        FileUtil.forceDelete( destination );
+        assertTrue( "Check No Exist", !destination.exists() );
+    }
+
+    public void testCopyFile1ToDir()
+        throws Exception
+    {
+        final File directory = new File( m_testDirectory, "subdir" );
+        if( !directory.exists() ) directory.mkdirs();
+        final File destination = new File( directory, "file1-test.txt" );
+        FileUtil.copyFileToDirectory( m_testFile1, directory );
+        assertTrue( "Check Exist", destination.exists() );
+        assertTrue( "Check Full copy", destination.length() == FILE1_SIZE );
+    }
+
+    public void testCopyFile2ToDir()
+        throws Exception
+    {
+        final File directory = new File( m_testDirectory, "subdir" );
+        if( !directory.exists() ) directory.mkdirs();
+        final File destination = new File( directory, "file2-test.txt" );
+        FileUtil.copyFileToDirectory( m_testFile2, directory );
+        assertTrue( "Check Exist", destination.exists() );
+        assertTrue( "Check Full copy", destination.length() == FILE2_SIZE );
+    }
+
+    public void testForceDeleteDir()
+        throws Exception
+    {
+        FileUtil.forceDelete( m_testDirectory.getParentFile() );
+        assertTrue( "Check No Exist", !m_testDirectory.getParentFile().exists() );
+    }
+
+    public void testResolveFileDotDot()
+        throws Exception
+    {
+        final File file = FileUtil.resolveFile( m_testDirectory, ".." );
+        assertEquals( "Check .. operator", file, m_testDirectory.getParentFile() );
+    }
+
+    public void testResolveFileDot()
+        throws Exception
+    {
+        final File file = FileUtil.resolveFile( m_testDirectory, "." );
+        assertEquals( "Check . operator", file, m_testDirectory );
+    }
+
+    public void testNormalize()
+        throws Exception
+    {
+        final String[] src =
+            {
+                "", "/", "///", "/foo", "/foo//", "/./", "/foo/./", "/foo/./bar",
+                "/foo/../bar", "/foo/../bar/../baz", "/foo/bar/../../baz", "/././",
+                "/foo/./../bar", "/foo/.././bar/", "//foo//./bar", "/../",
+                "/foo/../../"
+            };
+
+        final String[] dest =
+            {
+                "", "/", "/", "/foo", "/foo/", "/", "/foo/", "/foo/bar", "/bar",
+                "/baz", "/baz", "/", "/bar", "/bar/", "/foo/bar", null, null
+            };
+
+        assertEquals( "Oops, test writer goofed", src.length, dest.length );
+
+        for( int i = 0; i < src.length; i++ )
+        {
+            assertEquals( "Check if '" + src[ i ] + "' normalized to '" + dest[ i ] + "'",
+                          dest[ i ], FileUtil.normalize( src[ i ] ) );
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/IOTestSuite.java b/src/test/org/apache/commons/io/IOTestSuite.java
new file mode 100644
index 0000000..1d1b6e1
--- /dev/null
+++ b/src/test/org/apache/commons/io/IOTestSuite.java
@@ -0,0 +1,79 @@
+/*
+ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//io/src/test/org/apache/commons/io/Attic/IOTestSuite.java,v 1.1 2002/07/08 22:19:10 nicolaken Exp $
+ * $Revision: 1.1 $
+ * $Date: 2002/07/08 22:19:10 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.io;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * A basic test suite that tests all the IO package.
+ */
+public class IOTestSuite
+{
+    public static Test suite()
+    {
+        final TestSuite suite = new TestSuite( "IO Utilities" );
+        suite.addTest( new TestSuite( FileUtilTestCase.class ) );
+        suite.addTest( new TestSuite( IOUtilTestCase.class ) );
+        return suite;
+    }
+}
diff --git a/src/test/org/apache/commons/io/IOUtilTestCase.java b/src/test/org/apache/commons/io/IOUtilTestCase.java
new file mode 100644
index 0000000..8be1bc8
--- /dev/null
+++ b/src/test/org/apache/commons/io/IOUtilTestCase.java
@@ -0,0 +1,484 @@
+/*
+ * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//io/src/test/org/apache/commons/io/Attic/IOUtilTestCase.java,v 1.1 2002/07/08 22:19:10 nicolaken Exp $
+ * $Revision: 1.1 $
+ * $Date: 2002/07/08 22:19:10 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.io;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import org.apache.avalon.excalibur.io.FileUtil;
+import org.apache.avalon.excalibur.io.IOUtil;
+
+// Note: jdk1.2 dependency
+
+/**
+ * This is used to test IOUtil for correctness. The following checks are performed:
+ * <ul>
+ *   <li>The return must not be null, must be the same type and equals() to the method's second arg</li>
+ *   <li>All bytes must have been read from the source (available() == 0)</li>
+ *   <li>The source and destination content must be identical (byte-wise comparison check)</li>
+ *   <li>The output stream must not have been closed (a byte/char is written to test this, and
+ *   subsequent size checked)</li>
+ * </ul>
+ * Due to interdependencies in IOUtils and IOUtilsTestlet, one bug may cause
+ * multiple tests to fail.
+ *
+ * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
+ */
+public final class IOUtilTestCase
+    extends TestCase
+{
+    /*
+     * Note: this is not particularly beautiful code. A better way to check for
+     * flush and close status would be to implement "trojan horse" wrapper
+     * implementations of the various stream classes, which set a flag when
+     * relevant methods are called. (JT)
+     */
+
+    private final int FILE_SIZE = 1024 * 4 + 1;
+
+    private File m_testDirectory;
+    private File m_testFile;
+
+    public void setUp()
+    {
+        try
+        {
+            m_testDirectory = ( new File( "test/io/" ) ).getAbsoluteFile();
+            if( !m_testDirectory.exists() )
+            {
+                m_testDirectory.mkdirs();
+            }
+
+            m_testFile = new File( m_testDirectory, "file2-test.txt" );
+
+            createFile( m_testFile, FILE_SIZE );
+        }
+        catch( IOException ioe )
+        {
+            throw new RuntimeException( "Can't run this test because environment could not be built" );
+        }
+    }
+
+    public void tearDown()
+    {
+        try
+        {
+            FileUtil.deleteDirectory( "test" );
+        }
+        catch( IOException ioe )
+        {
+            // Ignore, because by this time, it is too late.
+        }
+    }
+
+    public IOUtilTestCase( String name )
+    {
+        super( name );
+    }
+
+    private void createFile( final File file, final long size )
+        throws IOException
+    {
+        final BufferedOutputStream output =
+            new BufferedOutputStream( new FileOutputStream( file ) );
+
+        for( int i = 0; i < size; i++ )
+        {
+            output.write( (byte)( i % 128 ) ); // nice varied byte pattern compatible with Readers and Writers
+        }
+
+        output.close();
+    }
+
+    /** Assert that the contents of two byte arrays are the same. */
+    private void assertEqualContent( final byte[] b0, final byte[] b1 )
+        throws IOException
+    {
+        assertTrue( "Content not equal according to java.util.Arrays#equals()", Arrays.equals( b0, b1 ) );
+    }
+
+    /** Assert that the content of two files is the same. */
+    private void assertEqualContent( final File f0, final File f1 )
+        throws IOException
+    {
+        final FileInputStream is0 = new FileInputStream( f0 );
+        final FileInputStream is1 = new FileInputStream( f1 );
+        final byte[] buf0 = new byte[ FILE_SIZE ];
+        final byte[] buf1 = new byte[ FILE_SIZE ];
+        int n0 = 0;
+        int n1 = 0;
+
+        while( -1 != n0 )
+        {
+            n0 = is0.read( buf0 );
+            n1 = is1.read( buf1 );
+            assertTrue( "The files " + f0 + " and " + f1 +
+                        " have differing number of bytes available (" + n0 +
+                        " vs " + n1 + ")", ( n0 == n1 ) );
+
+            assertTrue( "The files " + f0 + " and " + f1 +
+                        " have different content", Arrays.equals( buf0, buf1 ) );
+        }
+    }
+
+    /** Assert that the content of a file is equal to that in a byte[]. */
+    private void assertEqualContent( final byte[] b0, final File file )
+        throws IOException
+    {
+        final FileInputStream is = new FileInputStream( file );
+        byte[] b1 = new byte[ b0.length ];
+        int numRead = is.read( b1 );
+        assertTrue( "Different number of bytes", numRead == b0.length && is.available() == 0 );
+        for( int i = 0;
+             i < numRead;
+             assertTrue( "Byte " + i + " differs (" + b0[ i ] + " != " + b1[ i ] + ")", b0[ i ] == b1[ i ] ), i++
+            )
+            ;
+    }
+
+    public void testInputStreamToOutputStream()
+        throws Exception
+    {
+        final File destination = newFile( "copy1.txt" );
+        final FileInputStream fin = new FileInputStream( m_testFile );
+        final FileOutputStream fout = new FileOutputStream( destination );
+
+        IOUtil.copy( fin, fout );
+        assertTrue( "Not all bytes were read", fin.available() == 0 );
+        fout.flush();
+
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testInputStreamToWriter()
+        throws Exception
+    {
+        final File destination = newFile( "copy2.txt" );
+        final FileInputStream fin = new FileInputStream( m_testFile );
+        final FileWriter fout = new FileWriter( destination );
+
+        IOUtil.copy( fin, fout );
+
+        assertTrue( "Not all bytes were read", fin.available() == 0 );
+        fout.flush();
+
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testInputStreamToString()
+        throws Exception
+    {
+        final FileInputStream fin = new FileInputStream( m_testFile );
+        final String out = IOUtil.toString( fin );
+        assertNotNull( out );
+        assertTrue( "Not all bytes were read", fin.available() == 0 );
+        assertTrue( "Wrong output size: out.length()=" + out.length() +
+                    "!=" + FILE_SIZE, out.length() == FILE_SIZE );
+        fin.close();
+    }
+
+    public void testReaderToOutputStream()
+        throws Exception
+    {
+        final File destination = newFile( "copy3.txt" );
+        final FileReader fin = new FileReader( m_testFile );
+        final FileOutputStream fout = new FileOutputStream( destination );
+        IOUtil.copy( fin, fout );
+        //Note: this method *does* flush. It is equivalent to:
+        //  final OutputStreamWriter _out = new OutputStreamWriter(fout);
+        //  IOUtil.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
+        //  _out.flush();
+        //  out = fout;
+
+        // Note: rely on the method to flush
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testReaderToWriter()
+        throws Exception
+    {
+        final File destination = newFile( "copy4.txt" );
+        final FileReader fin = new FileReader( m_testFile );
+        final FileWriter fout = new FileWriter( destination );
+        IOUtil.copy( fin, fout );
+
+        fout.flush();
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testReaderToString()
+        throws Exception
+    {
+        final FileReader fin = new FileReader( m_testFile );
+        final String out = IOUtil.toString( fin );
+        assertNotNull( out );
+        assertTrue( "Wrong output size: out.length()=" +
+                    out.length() + "!=" + FILE_SIZE,
+                    out.length() == FILE_SIZE );
+        fin.close();
+    }
+
+    public void testStringToOutputStream()
+        throws Exception
+    {
+        final File destination = newFile( "copy5.txt" );
+        final FileReader fin = new FileReader( m_testFile );
+        // Create our String. Rely on testReaderToString() to make sure this is valid.
+        final String str = IOUtil.toString( fin );
+        final FileOutputStream fout = new FileOutputStream( destination );
+        IOUtil.copy( str, fout );
+        //Note: this method *does* flush. It is equivalent to:
+        //  final OutputStreamWriter _out = new OutputStreamWriter(fout);
+        //  IOUtil.copy( str, _out, 4096 ); // copy( Reader, Writer, int );
+        //  _out.flush();
+        //  out = fout;
+        // note: we don't flush here; this IOUtils method does it for us
+
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testStringToWriter()
+        throws Exception
+    {
+        final File destination = newFile( "copy6.txt" );
+        FileReader fin = new FileReader( m_testFile );
+        // Create our String. Rely on testReaderToString() to make sure this is valid.
+        final String str = IOUtil.toString( fin );
+        final FileWriter fout = new FileWriter( destination );
+        IOUtil.copy( str, fout );
+        fout.flush();
+
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+
+        deleteFile( destination );
+    }
+
+    public void testInputStreamToByteArray()
+        throws Exception
+    {
+        final FileInputStream fin = new FileInputStream( m_testFile );
+        final byte[] out = IOUtil.toByteArray( fin );
+        assertNotNull( out );
+        assertTrue( "Not all bytes were read", fin.available() == 0 );
+        assertTrue( "Wrong output size: out.length=" + out.length +
+                    "!=" + FILE_SIZE, out.length == FILE_SIZE );
+        assertEqualContent( out, m_testFile );
+        fin.close();
+    }
+
+    public void testStringToByteArray()
+        throws Exception
+    {
+        final FileReader fin = new FileReader( m_testFile );
+
+        // Create our String. Rely on testReaderToString() to make sure this is valid.
+        final String str = IOUtil.toString( fin );
+
+        final byte[] out = IOUtil.toByteArray( str );
+        assertEqualContent( str.getBytes(), out );
+        fin.close();
+    }
+
+    public void testByteArrayToWriter()
+        throws Exception
+    {
+        final File destination = newFile( "copy7.txt" );
+        final FileWriter fout = new FileWriter( destination );
+        final FileInputStream fin = new FileInputStream( m_testFile );
+
+        // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
+        final byte[] in = IOUtil.toByteArray( fin );
+        IOUtil.copy( in, fout );
+        fout.flush();
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+    public void testByteArrayToString()
+        throws Exception
+    {
+        final FileInputStream fin = new FileInputStream( m_testFile );
+        final byte[] in = IOUtil.toByteArray( fin );
+        // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
+        String str = IOUtil.toString( in );
+        assertEqualContent( in, str.getBytes() );
+        fin.close();
+    }
+
+    public void testByteArrayToOutputStream()
+        throws Exception
+    {
+        final File destination = newFile( "copy8.txt" );
+        final FileOutputStream fout = new FileOutputStream( destination );
+        final FileInputStream fin = new FileInputStream( m_testFile );
+
+        // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
+        final byte[] in = IOUtil.toByteArray( fin );
+
+        IOUtil.copy( in, fout );
+
+        fout.flush();
+
+        checkFile( destination );
+        checkWrite( fout );
+        fout.close();
+        fin.close();
+        deleteFile( destination );
+    }
+
+
+    //////////////////////////////////////////////////////
+    // xxxxxxxxx
+
+
+    private File newFile( String filename )
+        throws Exception
+    {
+        final File destination = new File( m_testDirectory, filename );
+        assertTrue( filename + "Test output data file shouldn't previously exist",
+                    !destination.exists() );
+
+        return destination;
+    }
+
+    private void checkFile( final File file )
+        throws Exception
+    {
+        assertTrue( "Check existence of output file", file.exists() );
+        assertEqualContent( m_testFile, file );
+    }
+
+    private void checkWrite( final OutputStream output )
+        throws Exception
+    {
+        try
+        {
+            new PrintStream( output ).write( 0 );
+        }
+        catch( final Throwable t )
+        {
+            throw new AssertionFailedError( "The copy() method closed the stream " +
+                                            "when it shouldn't have. " + t.getMessage() );
+        }
+    }
+
+    private void checkWrite( final Writer output )
+        throws Exception
+    {
+        try
+        {
+            new PrintWriter( output ).write( 'a' );
+        }
+        catch( final Throwable t )
+        {
+            throw new AssertionFailedError( "The copy() method closed the stream " +
+                                            "when it shouldn't have. " + t.getMessage() );
+        }
+    }
+
+    private void deleteFile( final File file )
+        throws Exception
+    {
+        assertTrue( "Wrong output size: file.length()=" +
+                    file.length() + "!=" + FILE_SIZE + 1,
+                    file.length() == FILE_SIZE + 1 );
+
+        //assertTrue( "File would not delete", (file.delete() || ( !file.exists() )));
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/bzip2/BzipTestCase.java b/src/test/org/apache/commons/io/compress/bzip2/BzipTestCase.java
new file mode 100644
index 0000000..ad4e4fa
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/bzip2/BzipTestCase.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included  with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.excalibur.bzip2.test;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import junit.framework.TestCase;
+import org.apache.excalibur.bzip2.CBZip2InputStream;
+import org.apache.excalibur.bzip2.CBZip2OutputStream;
+
+/**
+ * A test the stress tested the BZip implementation to verify
+ * that it behaves correctly.
+ *
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 1.1 $ $Date: 2002/07/08 22:19:09 $
+ */
+public class BzipTestCase
+    extends TestCase
+{
+    private static final byte[] HEADER = new byte[]{(byte)'B', (byte)'Z'};
+
+    public BzipTestCase( final String name )
+    {
+        super( name );
+    }
+
+    public void testBzipOutputStream()
+        throws Exception
+    {
+        final InputStream input = getInputStream( "asf-logo-huge.tar" );
+        final File outputFile = getOutputFile( ".tar.bz2" );
+        final OutputStream output = new FileOutputStream( outputFile );
+        final CBZip2OutputStream packedOutput = getPackedOutput( output );
+        copy( input, packedOutput );
+        shutdownStream( input );
+        shutdownStream( packedOutput );
+        shutdownStream( output );
+        compareContents( "asf-logo-huge.tar.bz2", outputFile );
+        forceDelete( outputFile );
+    }
+
+    private void forceDelete( final File outputFile ) throws IOException
+    {
+        if( !outputFile.delete() )
+        {
+            final String message = "File " + outputFile + " unable to be deleted.";
+            throw new IOException( message );
+        }
+    }
+
+    public void testBzipInputStream()
+        throws Exception
+    {
+        final InputStream input = getInputStream( "asf-logo-huge.tar.bz2" );
+        final File outputFile = getOutputFile( ".tar" );
+        final OutputStream output = new FileOutputStream( outputFile );
+        final CBZip2InputStream packedInput = getPackedInput( input );
+        copy( packedInput, output );
+        shutdownStream( input );
+        shutdownStream( packedInput );
+        shutdownStream( output );
+        compareContents( "asf-logo-huge.tar", outputFile );
+        forceDelete( outputFile );
+    }
+
+    /**
+     * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
+     */
+    private void copy( final InputStream input,
+                       final OutputStream output )
+        throws IOException
+    {
+        final byte[] buffer = new byte[ 8024 ];
+        int n = 0;
+        while( -1 != ( n = input.read( buffer ) ) )
+        {
+            output.write( buffer, 0, n );
+        }
+    }
+
+    private void compareContents( final String initial, final File generated )
+        throws Exception
+    {
+        final InputStream input1 = getInputStream( initial );
+        final InputStream input2 = new FileInputStream( generated );
+        final boolean test = contentEquals( input1, input2 );
+        shutdownStream( input1 );
+        shutdownStream( input2 );
+        assertTrue( "Contents of " + initial + " matches generated version " + generated, test );
+    }
+
+    private CBZip2InputStream getPackedInput( final InputStream input )
+        throws IOException
+    {
+        final int b1 = input.read();
+        final int b2 = input.read();
+        assertEquals( "Equal header byte1", b1, 'B' );
+        assertEquals( "Equal header byte2", b2, 'Z' );
+        return new CBZip2InputStream( input );
+    }
+
+    private CBZip2OutputStream getPackedOutput( final OutputStream output )
+        throws IOException
+    {
+        output.write( HEADER );
+        return new CBZip2OutputStream( output );
+    }
+
+    private File getOutputFile( final String postfix )
+        throws IOException
+    {
+        final File cwd = new File( "." );
+        return File.createTempFile( "ant-test", postfix, cwd );
+    }
+
+    private InputStream getInputStream( final String resource )
+        throws Exception
+    {
+        final String filename = ".." + File.separator + ".." + File.separator +
+            "src" + File.separator + "test" + File.separator +
+            getClass().getName().replace( '.', File.separatorChar );
+        final String path = getPath( filename );
+        final File input = new File( path, resource );
+        return new FileInputStream( input );
+        //final ClassLoader loader = getClass().getClassLoader();
+        //return loader.getResourceAsStream( resource );
+    }
+
+    /**
+     * Compare the contents of two Streams to determine if they are equal or not.
+     *
+     * @param input1 the first stream
+     * @param input2 the second stream
+     * @return true if the content of the streams are equal or they both don't exist, false otherwise
+     */
+    private boolean contentEquals( final InputStream input1,
+                                   final InputStream input2 )
+        throws IOException
+    {
+        final InputStream bufferedInput1 = new BufferedInputStream( input1 );
+        final InputStream bufferedInput2 = new BufferedInputStream( input2 );
+
+        int ch = bufferedInput1.read();
+        while( -1 != ch )
+        {
+            final int ch2 = bufferedInput2.read();
+            if( ch != ch2 )
+            {
+                return false;
+            }
+            ch = bufferedInput1.read();
+        }
+
+        final int ch2 = bufferedInput2.read();
+        if( -1 != ch2 )
+        {
+            return false;
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    private String getPath( final String filepath )
+    {
+        final int index = filepath.lastIndexOf( File.separatorChar );
+        if( -1 == index )
+        {
+            return "";
+        }
+        else
+        {
+            return filepath.substring( 0, index );
+        }
+    }
+
+    /**
+     * Unconditionally close an <code>OutputStream</code>.
+     * Equivalent to {@link java.io.OutputStream#close()}, except any exceptions will be ignored.
+     * @param output A (possibly null) OutputStream
+     */
+    private static void shutdownStream( final OutputStream output )
+    {
+        if( null == output )
+        {
+            return;
+        }
+
+        try
+        {
+            output.close();
+        }
+        catch( final IOException ioe )
+        {
+        }
+    }
+
+    /**
+     * Unconditionally close an <code>InputStream</code>.
+     * Equivalent to {@link java.io.InputStream#close()}, except any exceptions will be ignored.
+     * @param input A (possibly null) InputStream
+     */
+    private static void shutdownStream( final InputStream input )
+    {
+        if( null == input )
+        {
+            return;
+        }
+
+        try
+        {
+            input.close();
+        }
+        catch( final IOException ioe )
+        {
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar b/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar
new file mode 100644
index 0000000..3f92609
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar
Binary files differ
diff --git a/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar.bz2 b/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar.bz2
new file mode 100644
index 0000000..7c2d215
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/bzip2/asf-logo-huge.tar.bz2
Binary files differ
diff --git a/src/test/org/apache/commons/io/compress/tar/TarTestCase.java b/src/test/org/apache/commons/io/compress/tar/TarTestCase.java
new file mode 100644
index 0000000..c9c6269
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/TarTestCase.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.compress.tar;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import junit.framework.TestCase;
+import org.apache.excalibur.tar.TarEntry;
+import org.apache.excalibur.tar.TarInputStream;
+import org.apache.excalibur.tar.TarOutputStream;
+
+/**
+ * Test case for all tar resources.
+ *
+ * @todo Find V7 tar and do tests against it
+ * @author <a href="mailto:peter@apache.org">Peter Donald</a>
+ * @version $Revision: 1.1 $ $Date: 2002/07/08 22:19:10 $
+ */
+public final class TarTestCase
+    extends TestCase
+{
+    private static final char SP = File.separatorChar;
+    private static final String BASE_DATA_NAME = "data.txt";
+    private static final String LFN_PART = "a-b-c-d-e-f-g-h-i-j/";
+    private static final String LONG_FILE_NAME =
+        LFN_PART + LFN_PART + LFN_PART + LFN_PART + LFN_PART + "a";
+
+    private static final String BASEDIR = calcBaseDir();
+
+    private static final File BASEDIR_FILE = new File( BASEDIR );
+    private static final File POSIX_TAR_FILE =
+        new File( BASEDIR_FILE, "posix.tar" );
+    //    private static final File V7_TAR_FILE =
+    //        new File( BASEDIR_FILE, "v7.tar" );
+    private static final File GNU_TAR_FILE =
+        new File( BASEDIR_FILE, "gnu.tar" );
+    private static final File DATA_FILE1 =
+        new File( BASEDIR_FILE, BASE_DATA_NAME );
+    private static final String USER_NAME = "avalon";
+    private static final String GROUP_NAME = "excalibur";
+    private static final long SIZE = DATA_FILE1.length();
+    private static final int GROUP_ID = 0;
+    private static final int USER_ID = 0;
+    private static final int MODE = 0100000;
+    private static final int MOD_TIME = 0;
+
+    public TarTestCase()
+    {
+        this( "Tar Test Case" );
+    }
+
+    public TarTestCase( String name )
+    {
+        super( name );
+    }
+
+    private static String calcBaseDir()
+    {
+        final String name = TarTestCase.class.getName();
+        final int size = name.length();
+        final String filename =
+            name.substring( 0, size - 11 ).replace( '.', SP );
+        return ".." + SP + ".." + SP +
+            "src" + SP + "test" + SP + filename + SP;
+    }
+
+    public void testReadPosixTar()
+        throws Exception
+    {
+        compareTar( BASE_DATA_NAME, POSIX_TAR_FILE );
+    }
+
+    public void testReadGnuTar()
+        throws Exception
+    {
+        compareTar( LONG_FILE_NAME, GNU_TAR_FILE );
+    }
+
+    public void testWritePosixTar()
+        throws Exception
+    {
+        //final File temp = new File( BASEDIR_FILE, "posix2.tar" );
+        final File temp = File.createTempFile( "delete-me", "tar" );
+        final FileOutputStream fileOutput = new FileOutputStream( temp );
+        final TarOutputStream output = new TarOutputStream( fileOutput );
+        //output.setBufferDebug( true );
+        final TarEntry entry = new TarEntry( BASE_DATA_NAME );
+        setupEntry( entry );
+        output.putNextEntry( entry );
+
+        final FileInputStream fileInput = new FileInputStream( DATA_FILE1 );
+        output.copyEntryContents( fileInput );
+        output.closeEntry();
+        shutdownStream( fileInput );
+        shutdownStream( output );
+        shutdownStream( fileOutput );
+
+        assertTrue( "Tar files Equal", contentEquals( temp, POSIX_TAR_FILE ) );
+        temp.delete();
+    }
+
+    public void testWriteGnuTar()
+        throws Exception
+    {
+        //final File temp = new File( BASEDIR_FILE, "gnu2.tar" );
+        final File temp = File.createTempFile( "delete-me", "tar" );
+        final FileOutputStream fileOutput = new FileOutputStream( temp );
+        final TarOutputStream output = new TarOutputStream( fileOutput );
+        //output.setBufferDebug( true );
+        output.setLongFileMode( TarOutputStream.LONGFILE_GNU );
+        final TarEntry entry = new TarEntry( LONG_FILE_NAME );
+        setupEntry( entry );
+        output.putNextEntry( entry );
+
+        final FileInputStream fileInput = new FileInputStream( DATA_FILE1 );
+        output.copyEntryContents( fileInput );
+        output.closeEntry();
+        shutdownStream( fileInput );
+        shutdownStream( output );
+        shutdownStream( fileOutput );
+
+        //Have to compare it this way as the contents will differ
+        //due to entry created for second part of name
+        compareTar( LONG_FILE_NAME, temp );
+        temp.delete();
+    }
+
+    private void setupEntry( final TarEntry entry )
+    {
+        entry.setModTime( MOD_TIME );
+        entry.setSize( SIZE );
+        entry.setUserID( USER_ID );
+        entry.setGroupID( GROUP_ID );
+        entry.setUserName( USER_NAME );
+        entry.setGroupName( GROUP_NAME );
+        entry.setMode( MODE );
+    }
+
+    private void checkEntry( final TarEntry entry )
+    {
+        assertEquals( "Entry size", SIZE, entry.getSize() );
+        assertEquals( "Entry User ID", USER_ID, entry.getUserID() );
+        assertEquals( "Entry Group ID", GROUP_ID, entry.getGroupID() );
+        assertEquals( "Entry User name", USER_NAME, entry.getUserName() );
+        assertEquals( "Entry group name", GROUP_NAME, entry.getGroupName() );
+        assertEquals( "Entry mode", MODE, entry.getMode() );
+        assertEquals( "Entry mode", MOD_TIME, entry.getModTime().getTime() / 1000 );
+    }
+
+    /**
+     * Read tar entry with specified name from tar file1 and compare
+     * against data file DATA_FILE1.
+     *
+     * @param entryName the expected name of entry
+     * @param file1 the tar file comparing
+     * @throws IOException if an error occurs
+     */
+    private void compareTar( final String entryName,
+                             final File file1 )
+        throws IOException
+    {
+        final FileInputStream fileInput = new FileInputStream( file1 );
+        final TarInputStream input = new TarInputStream( fileInput );
+        //input.setDebug( true );
+        final TarEntry entry = input.getNextEntry();
+
+        assertEquals( "Entry name", entryName, entry.getName() );
+        checkEntry( entry );
+
+        final File temp = new File( BASEDIR_FILE, entryName.length() + "data.txt" );//File.createTempFile( "delete-me", "tar" );
+        final FileOutputStream output = new FileOutputStream( temp );
+        input.copyEntryContents( output );
+        shutdownStream( output );
+
+        assertNull( "Next Entry", input.getNextEntry() );
+
+        shutdownStream( input );
+
+        assertTrue( "Data Equals", contentEquals( temp, DATA_FILE1 ) );
+        temp.delete();
+    }
+
+    /**
+     * Compare the contents of two files to determine if they are equal or not.
+     *
+     * @param file1 the first file
+     * @param file2 the second file
+     * @return true if the content of the files are equal or they both don't exist, false otherwise
+     */
+    private boolean contentEquals( final File file1, final File file2 )
+        throws IOException
+    {
+        final boolean file1Exists = file1.exists();
+        if( file1Exists != file2.exists() )
+        {
+            return false;
+        }
+
+        if( !file1Exists )
+        {
+            // two not existing files are equal
+            return true;
+        }
+
+        if( file1.isDirectory() || file2.isDirectory() )
+        {
+            // don't want to compare directory contents
+            return false;
+        }
+
+        InputStream input1 = null;
+        InputStream input2 = null;
+        try
+        {
+            input1 = new FileInputStream( file1 );
+            input2 = new FileInputStream( file2 );
+            return contentEquals( input1, input2 );
+
+        }
+        finally
+        {
+            shutdownStream( input1 );
+            shutdownStream( input2 );
+        }
+    }
+
+    /**
+     * Compare the contents of two Streams to determine if they are equal or not.
+     *
+     * @param input1 the first stream
+     * @param input2 the second stream
+     * @return true if the content of the streams are equal or they both don't exist, false otherwise
+     */
+    private boolean contentEquals( final InputStream input1,
+                                   final InputStream input2 )
+        throws IOException
+    {
+        final InputStream bufferedInput1 = new BufferedInputStream( input1 );
+        final InputStream bufferedInput2 = new BufferedInputStream( input2 );
+
+        int count = 0;
+        int ch = bufferedInput1.read();
+        while( -1 != ch )
+        {
+            final int ch2 = bufferedInput2.read();
+            count++;
+            if( ch != ch2 )
+            {
+                System.out.println( "count = " + count );
+                System.out.println( "ch2 = " + ch2 );
+                System.out.println( "ch = " + ch );
+                return false;
+            }
+            ch = bufferedInput1.read();
+        }
+
+        final int ch2 = bufferedInput2.read();
+        if( -1 != ch2 )
+        {
+            return false;
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    private void shutdownStream( final InputStream input )
+    {
+        if( null == input )
+        {
+            return;
+        }
+
+        try
+        {
+            input.close();
+        }
+        catch( final IOException ioe )
+        {
+        }
+    }
+
+    private void shutdownStream( final OutputStream output )
+    {
+        if( null == output )
+        {
+            return;
+        }
+
+        try
+        {
+            output.close();
+        }
+        catch( final IOException ioe )
+        {
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/tar/TarTestSuite.java b/src/test/org/apache/commons/io/compress/tar/TarTestSuite.java
new file mode 100644
index 0000000..96baafc
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/TarTestSuite.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright  The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.compress.tar;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * A basic test suite that tests all the tar package.
+ */
+public class TarTestSuite
+{
+    public static Test suite()
+    {
+        final TestSuite suite = new TestSuite( "Tar Utilities" );
+        return suite;
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/tar/data.txt b/src/test/org/apache/commons/io/compress/tar/data.txt
new file mode 100644
index 0000000..f03277e
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/data.txt
@@ -0,0 +1,15 @@
+    One of the greatest benefactors of all lifekind was a man who
+couldn't keep his mind on the job at hand.
+    Brilliant?
+    Certainly.
+    One of the foremost genetic engineers of his or any other
+generation, including a number he had designed himself?
+    Without a doubt.
+    The problem was that he was far too interested in things which
+he shouldn't be interested in, at least as people would tell him,
+not now.
+    He was also, partly because of this, of a rather irritable
+disposition.
+    So when the world was threatened by terrible invaders from a
+distant star, who were still a fair way off but traveling fast,
+he, Blart Versenwald III...
\ No newline at end of file
diff --git a/src/test/org/apache/commons/io/compress/tar/gnu.tar b/src/test/org/apache/commons/io/compress/tar/gnu.tar
new file mode 100644
index 0000000..22f006a
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/gnu.tar
Binary files differ
diff --git a/src/test/org/apache/commons/io/compress/tar/posix.tar b/src/test/org/apache/commons/io/compress/tar/posix.tar
new file mode 100644
index 0000000..8044616
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/posix.tar
Binary files differ
diff --git a/src/test/org/apache/commons/io/compress/tar/update-tars.bat b/src/test/org/apache/commons/io/compress/tar/update-tars.bat
new file mode 100644
index 0000000..355b2f2
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/tar/update-tars.bat
@@ -0,0 +1,3 @@
+copy gnu2.tar gnu.tar
+copy posix2.tar posix.tar
+pause
\ No newline at end of file
diff --git a/src/test/org/apache/commons/io/compress/zip/AsiExtraFieldTestCase.java b/src/test/org/apache/commons/io/compress/zip/AsiExtraFieldTestCase.java
new file mode 100644
index 0000000..059f3af
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/zip/AsiExtraFieldTestCase.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.io.compress.zip;
+
+import java.util.zip.ZipException;
+import junit.framework.TestCase;
+import org.apache.excalibur.zip.AsiExtraField;
+import org.apache.excalibur.zip.UnixStat;
+
+/**
+ * JUnit testcases AsiExtraField.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+public class AsiExtraFieldTestCase
+    extends TestCase
+    implements UnixStat
+{
+    public AsiExtraFieldTestCase( final String name )
+    {
+        super( name );
+    }
+
+    /**
+     * Test file mode magic.
+     */
+    public void testModes()
+    {
+        final AsiExtraField field = new AsiExtraField();
+        field.setMode( 0123 );
+        assertEquals( "plain file", 0100123, field.getMode() );
+        field.setDirectory( true );
+        assertEquals( "directory", 040123, field.getMode() );
+        field.setLinkedFile( "test" );
+        assertEquals( "symbolic link", 0120123, field.getMode() );
+    }
+
+    private AsiExtraField createField()
+    {
+        final AsiExtraField field = new AsiExtraField();
+        field.setMode( 0123 );
+        field.setUserId( 5 );
+        field.setGroupId( 6 );
+        return field;
+    }
+
+    public void testContent1()
+    {
+        final AsiExtraField field = createField();
+        final byte[] data = field.getLocalFileDataData();
+
+        // CRC manually calculated, sorry
+        final byte[] expect = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC
+                               0123, (byte)0x80, // mode
+                               0, 0, 0, 0, // link length
+                               5, 0, 6, 0};                        // uid, gid
+        assertEquals( "no link", expect.length, data.length );
+        for( int i = 0; i < expect.length; i++ )
+        {
+            assertEquals( "no link, byte " + i, expect[ i ], data[ i ] );
+        }
+
+        field.setLinkedFile( "test" );
+    }
+
+    public void testContent2()
+    {
+        final AsiExtraField field = createField();
+        field.setLinkedFile( "test" );
+
+        final byte[] data = field.getLocalFileDataData();
+        final byte[] expect = new byte[]{0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC
+                                         0123, (byte)0xA0, // mode
+                                         4, 0, 0, 0, // link length
+                                         5, 0, 6, 0, // uid, gid
+                                         (byte)'t', (byte)'e', (byte)'s', (byte)'t'};
+        assertEquals( "no link", expect.length, data.length );
+        for( int i = 0; i < expect.length; i++ )
+        {
+            assertEquals( "no link, byte " + i, expect[ i ], data[ i ] );
+        }
+
+    }
+
+    public void testReparse1()
+        throws ZipException
+    {
+        // CRC manually calculated, sorry
+        final byte[] data = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC
+                             0123, (byte)0x80, // mode
+                             0, 0, 0, 0, // link length
+                             5, 0, 6, 0};                        // uid, gid
+        final AsiExtraField field = new AsiExtraField();
+        field.parseFromLocalFileData( data, 0, data.length );
+
+        assertEquals( "length plain file", data.length,
+                      field.getLocalFileDataLength().getValue() );
+        assertTrue( "plain file, no link", !field.isLink() );
+        assertTrue( "plain file, no dir", !field.isDirectory() );
+        assertEquals( "mode plain file", FILE_FLAG | 0123, field.getMode() );
+        assertEquals( "uid plain file", 5, field.getUserId() );
+        assertEquals( "gid plain file", 6, field.getGroupID() );
+    }
+
+    public void testReparse2()
+        throws ZipException
+    {
+        final byte[] data = new byte[]{0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC
+                                       0123, (byte)0xA0, // mode
+                                       4, 0, 0, 0, // link length
+                                       5, 0, 6, 0, // uid, gid
+                                       (byte)'t', (byte)'e', (byte)'s', (byte)'t'};
+        final AsiExtraField field = new AsiExtraField();
+        field.parseFromLocalFileData( data, 0, data.length );
+        assertEquals( "length link", data.length,
+                      field.getLocalFileDataLength().getValue() );
+        assertTrue( "link, is link", field.isLink() );
+        assertTrue( "link, no dir", !field.isDirectory() );
+        assertEquals( "mode link", LINK_FLAG | 0123, field.getMode() );
+        assertEquals( "uid link", 5, field.getUserId() );
+        assertEquals( "gid link", 6, field.getGroupID() );
+        assertEquals( "test", field.getLinkedFile() );
+    }
+
+    public void testReparse3()
+        throws ZipException
+    {
+        final byte[] data = new byte[]{(byte)0x8E, 0x01, (byte)0xBF, (byte)0x0E, // CRC
+                                       0123, (byte)0x40, // mode
+                                       0, 0, 0, 0, // link
+                                       5, 0, 6, 0};                          // uid, gid
+        final AsiExtraField field = new AsiExtraField();
+        field.parseFromLocalFileData( data, 0, data.length );
+        assertEquals( "length dir", data.length,
+                      field.getLocalFileDataLength().getValue() );
+        assertTrue( "dir, no link", !field.isLink() );
+        assertTrue( "dir, is dir", field.isDirectory() );
+        assertEquals( "mode dir", DIR_FLAG | 0123, field.getMode() );
+        assertEquals( "uid dir", 5, field.getUserId() );
+        assertEquals( "gid dir", 6, field.getGroupID() );
+    }
+
+    public void testReparse4()
+        throws Exception
+    {
+        final byte[] data = new byte[]{0, 0, 0, 0, // bad CRC
+                                       0123, (byte)0x40, // mode
+                                       0, 0, 0, 0, // link
+                                       5, 0, 6, 0};                          // uid, gid
+        final AsiExtraField field = new AsiExtraField();
+        try
+        {
+            field.parseFromLocalFileData( data, 0, data.length );
+            fail( "should raise bad CRC exception" );
+        }
+        catch( Exception e )
+        {
+            assertEquals( "bad CRC checksum 0 instead of ebf018e",
+                          e.getMessage() );
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/zip/ExtraFieldUtilsTestCase.java b/src/test/org/apache/commons/io/compress/zip/ExtraFieldUtilsTestCase.java
new file mode 100644
index 0000000..b6eeb53
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/zip/ExtraFieldUtilsTestCase.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.io.compress.zip;
+
+import junit.framework.TestCase;
+import org.apache.excalibur.zip.AsiExtraField;
+import org.apache.excalibur.zip.ExtraFieldUtils;
+import org.apache.excalibur.zip.UnixStat;
+import org.apache.excalibur.zip.UnrecognizedExtraField;
+import org.apache.excalibur.zip.ZipExtraField;
+import org.apache.excalibur.zip.ZipShort;
+
+/**
+ * JUnit testcases ExtraFieldUtils.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+public class ExtraFieldUtilsTestCase
+    extends TestCase
+    implements UnixStat
+{
+    private AsiExtraField m_field;
+    private UnrecognizedExtraField m_dummy;
+    private byte[] m_data;
+    private byte[] m_local;
+
+    public ExtraFieldUtilsTestCase( final String name )
+    {
+        super( name );
+    }
+
+    public void setUp()
+    {
+        m_field = new AsiExtraField();
+        m_field.setMode( 0755 );
+        m_field.setDirectory( true );
+        m_dummy = new UnrecognizedExtraField();
+        m_dummy.setHeaderId( new ZipShort( 1 ) );
+        m_dummy.setLocalFileDataData( new byte[ 0 ] );
+        m_dummy.setCentralDirectoryData( new byte[]{0} );
+
+        m_local = m_field.getLocalFileDataData();
+        final byte[] dummyLocal = m_dummy.getLocalFileDataData();
+        m_data = new byte[ 4 + m_local.length + 4 + dummyLocal.length ];
+        System.arraycopy( m_field.getHeaderID().getBytes(), 0, m_data, 0, 2 );
+        System.arraycopy( m_field.getLocalFileDataLength().getBytes(), 0, m_data, 2, 2 );
+        System.arraycopy( m_local, 0, m_data, 4, m_local.length );
+        System.arraycopy( m_dummy.getHeaderID().getBytes(), 0, m_data,
+                          4 + m_local.length, 2 );
+        System.arraycopy( m_dummy.getLocalFileDataLength().getBytes(), 0, m_data,
+                          4 + m_local.length + 2, 2 );
+        System.arraycopy( dummyLocal, 0, m_data,
+                          4 + m_local.length + 4, dummyLocal.length );
+
+    }
+
+    /**
+     * test parser.
+     */
+    public void testParse() throws Exception
+    {
+        final ZipExtraField[] extraField = ExtraFieldUtils.parse( m_data );
+        assertEquals( "number of fields", 2, extraField.length );
+        assertTrue( "type field 1", extraField[ 0 ] instanceof AsiExtraField );
+        assertEquals( "mode field 1", 040755,
+                      ( (AsiExtraField)extraField[ 0 ] ).getMode() );
+        assertTrue( "type field 2", extraField[ 1 ] instanceof UnrecognizedExtraField );
+        assertEquals( "data length field 2", 0,
+                      extraField[ 1 ].getLocalFileDataLength().getValue() );
+
+        final byte[] data2 = new byte[ m_data.length - 1 ];
+        System.arraycopy( m_data, 0, data2, 0, data2.length );
+        try
+        {
+            ExtraFieldUtils.parse( data2 );
+            fail( "data should be invalid" );
+        }
+        catch( Exception e )
+        {
+            assertEquals( "message",
+                          "data starting at " + ( 4 + m_local.length ) + " is in unknown format",
+                          e.getMessage() );
+        }
+    }
+
+    /**
+     * Test merge methods
+     */
+    public void testMerge()
+    {
+        final byte[] local =
+            ExtraFieldUtils.mergeLocalFileDataData( new ZipExtraField[]{m_field, m_dummy} );
+        assertEquals( "local length", m_data.length, local.length );
+        for( int i = 0; i < local.length; i++ )
+        {
+            assertEquals( "local byte " + i, m_data[ i ], local[ i ] );
+        }
+
+        final byte[] dummyCentral = m_dummy.getCentralDirectoryData();
+        final byte[] data2 = new byte[ 4 + m_local.length + 4 + dummyCentral.length ];
+        System.arraycopy( m_data, 0, data2, 0, 4 + m_local.length + 2 );
+        System.arraycopy( m_dummy.getCentralDirectoryLength().getBytes(), 0,
+                          data2, 4 + m_local.length + 2, 2 );
+        System.arraycopy( dummyCentral, 0, data2,
+                          4 + m_local.length + 4, dummyCentral.length );
+
+        final byte[] central =
+            ExtraFieldUtils.mergeCentralDirectoryData( new ZipExtraField[]{m_field, m_dummy} );
+        assertEquals( "central length", data2.length, central.length );
+        for( int i = 0; i < central.length; i++ )
+        {
+            assertEquals( "central byte " + i, data2[ i ], central[ i ] );
+        }
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/zip/ZipEntryTestCase.java b/src/test/org/apache/commons/io/compress/zip/ZipEntryTestCase.java
new file mode 100644
index 0000000..8fc5d9d
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/zip/ZipEntryTestCase.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.io.compress.zip;
+
+import java.util.NoSuchElementException;
+import junit.framework.TestCase;
+import org.apache.excalibur.zip.AsiExtraField;
+import org.apache.excalibur.zip.UnrecognizedExtraField;
+import org.apache.excalibur.zip.ZipEntry;
+import org.apache.excalibur.zip.ZipExtraField;
+import org.apache.excalibur.zip.ZipShort;
+
+/**
+ * JUnit testcases ZipEntry.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+public class ZipEntryTestCase
+    extends TestCase
+{
+    public ZipEntryTestCase( final String name )
+    {
+        super( name );
+    }
+
+    /**
+     * test handling of extra fields
+     */
+    public void testExtraFields()
+    {
+        final AsiExtraField field = createField();
+        final UnrecognizedExtraField extraField = createExtraField();
+
+        final ZipEntry entry = new ZipEntry( "test/" );
+        entry.setExtraFields( new ZipExtraField[]{field, extraField} );
+        final byte[] data1 = entry.getExtra();
+        ZipExtraField[] result = entry.getExtraFields();
+        assertEquals( "first pass", 2, result.length );
+        assertSame( field, result[ 0 ] );
+        assertSame( extraField, result[ 1 ] );
+
+        UnrecognizedExtraField u2 = new UnrecognizedExtraField();
+        u2.setHeaderId( new ZipShort( 1 ) );
+        u2.setLocalFileDataData( new byte[]{1} );
+
+        entry.addExtraField( u2 );
+        byte[] data2 = entry.getExtra();
+        result = entry.getExtraFields();
+        assertEquals( "second pass", 2, result.length );
+        assertSame( field, result[ 0 ] );
+        assertSame( u2, result[ 1 ] );
+        assertEquals( "length second pass", data1.length + 1, data2.length );
+
+        UnrecognizedExtraField u3 = new UnrecognizedExtraField();
+        u3.setHeaderId( new ZipShort( 2 ) );
+        u3.setLocalFileDataData( new byte[]{1} );
+        entry.addExtraField( u3 );
+        result = entry.getExtraFields();
+        assertEquals( "third pass", 3, result.length );
+
+        entry.removeExtraField( new ZipShort( 1 ) );
+        byte[] data3 = entry.getExtra();
+        result = entry.getExtraFields();
+        assertEquals( "fourth pass", 2, result.length );
+        assertSame( field, result[ 0 ] );
+        assertSame( u3, result[ 1 ] );
+        assertEquals( "length fourth pass", data2.length, data3.length );
+
+        try
+        {
+            entry.removeExtraField( new ZipShort( 1 ) );
+            fail( "should be no such element" );
+        }
+        catch( final NoSuchElementException nse )
+        {
+        }
+    }
+
+    private UnrecognizedExtraField createExtraField()
+    {
+        UnrecognizedExtraField extraField = new UnrecognizedExtraField();
+        extraField.setHeaderId( new ZipShort( 1 ) );
+        extraField.setLocalFileDataData( new byte[ 0 ] );
+        return extraField;
+    }
+
+    private AsiExtraField createField()
+    {
+        final AsiExtraField field = new AsiExtraField();
+        field.setDirectory( true );
+        field.setMode( 0755 );
+        return field;
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/zip/ZipLongTestCase.java b/src/test/org/apache/commons/io/compress/zip/ZipLongTestCase.java
new file mode 100644
index 0000000..065c17a
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/zip/ZipLongTestCase.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.io.compress.zip;
+
+import junit.framework.TestCase;
+import org.apache.excalibur.zip.ZipLong;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ZipLong.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+public class ZipLongTestCase
+    extends TestCase
+{
+
+    public ZipLongTestCase( final String name )
+    {
+        super( name );
+    }
+
+    /**
+     * Test conversion to bytes.
+     */
+    public void testToBytes()
+    {
+        final ZipLong zipLong = new ZipLong( 0x12345678 );
+        final byte[] result = zipLong.getBytes();
+        assertEquals( "length getBytes", 4, result.length );
+        assertEquals( "first byte getBytes", 0x78, result[ 0 ] );
+        assertEquals( "second byte getBytes", 0x56, result[ 1 ] );
+        assertEquals( "third byte getBytes", 0x34, result[ 2 ] );
+        assertEquals( "fourth byte getBytes", 0x12, result[ 3 ] );
+    }
+
+    /**
+     * Test conversion from bytes.
+     */
+    public void testFromBytes()
+    {
+        final byte[] value = new byte[]{0x78, 0x56, 0x34, 0x12};
+        final ZipLong zipLong = new ZipLong( value );
+        assertEquals( "value from bytes", 0x12345678, zipLong.getValue() );
+    }
+
+    /**
+     * Test the contract of the equals method.
+     */
+    public void testEquals()
+    {
+        final ZipLong zipLong1 = new ZipLong( 0x12345678 );
+        final ZipLong zipLong2 = new ZipLong( 0x12345678 );
+        final ZipLong zipLong3 = new ZipLong( 0x87654321 );
+
+        assertTrue( "reflexive", zipLong1.equals( zipLong1 ) );
+
+        assertTrue( "works", zipLong1.equals( zipLong2 ) );
+        assertTrue( "works, part two", !zipLong1.equals( zipLong3 ) );
+
+        assertTrue( "symmetric", zipLong2.equals( zipLong1 ) );
+
+        assertTrue( "null handling", !zipLong1.equals( null ) );
+        assertTrue( "non ZipLong handling", !zipLong1.equals( new Integer( 0x1234 ) ) );
+    }
+
+    /**
+     * Test sign handling.
+     */
+    public void testSign()
+    {
+        final ZipLong zipLong =
+            new ZipLong( new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF} );
+        assertEquals( 0x00000000FFFFFFFFl, zipLong.getValue() );
+    }
+}
diff --git a/src/test/org/apache/commons/io/compress/zip/ZipShortTestCase.java b/src/test/org/apache/commons/io/compress/zip/ZipShortTestCase.java
new file mode 100644
index 0000000..cef8dc9
--- /dev/null
+++ b/src/test/org/apache/commons/io/compress/zip/ZipShortTestCase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.commons.io.compress.zip;
+
+import junit.framework.TestCase;
+import org.apache.excalibur.zip.ZipShort;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ZipShort.
+ *
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+public class ZipShortTestCase
+    extends TestCase
+{
+    public ZipShortTestCase( String name )
+    {
+        super( name );
+    }
+
+    /**
+     * Test conversion to bytes.
+     */
+    public void testToBytes()
+    {
+        final ZipShort zipShort = new ZipShort( 0x1234 );
+        byte[] result = zipShort.getBytes();
+        assertEquals( "length getBytes", 2, result.length );
+        assertEquals( "first byte getBytes", 0x34, result[ 0 ] );
+        assertEquals( "second byte getBytes", 0x12, result[ 1 ] );
+    }
+
+    /**
+     * Test conversion from bytes.
+     */
+    public void testFromBytes()
+    {
+        byte[] val = new byte[]{0x34, 0x12};
+        final ZipShort zipShort = new ZipShort( val );
+        assertEquals( "value from bytes", 0x1234, zipShort.getValue() );
+    }
+
+    /**
+     * Test the contract of the equals method.
+     */
+    public void testEquals()
+    {
+        final ZipShort zipShort = new ZipShort( 0x1234 );
+        final ZipShort zipShort2 = new ZipShort( 0x1234 );
+        final ZipShort zipShort3 = new ZipShort( 0x5678 );
+
+        assertTrue( "reflexive", zipShort.equals( zipShort ) );
+
+        assertTrue( "works", zipShort.equals( zipShort2 ) );
+        assertTrue( "works, part two", !zipShort.equals( zipShort3 ) );
+
+        assertTrue( "symmetric", zipShort2.equals( zipShort ) );
+
+        assertTrue( "null handling", !zipShort.equals( null ) );
+        assertTrue( "non ZipShort handling", !zipShort.equals( new Integer( 0x1234 ) ) );
+    }
+
+    /**
+     * Test sign handling.
+     */
+    public void testSign()
+    {
+        final ZipShort zipShort = new ZipShort( new byte[]{(byte)0xFF, (byte)0xFF} );
+        assertEquals( 0x0000FFFF, zipShort.getValue() );
+    }
+}