org.zeroturnaround.zip.ZipsTest.java Source code

Java tutorial

Introduction

Here is the source code for org.zeroturnaround.zip.ZipsTest.java

Source

package org.zeroturnaround.zip;
/**
 *    Copyright (C) 2012 ZeroTurnaround LLC <support@zeroturnaround.com>
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import junit.framework.TestCase;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformer;

public class ZipsTest extends TestCase {

    public void testDuplicateEntryAtAdd() throws IOException {
        File src = new File("src/test/resources/duplicate.zip");

        File dest = File.createTempFile("temp", ".zip");
        try {
            Zips.get(src).addEntries(new ZipEntrySource[0]).destination(dest).process();
        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testAddEntry() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);
        final String fileName = "TestFile.txt";
        assertFalse(ZipUtil.containsEntry(src, fileName));

        File newEntry = new File("src/test/resources/" + fileName);
        File dest = File.createTempFile("temp.zip", ".zip");

        Zips.get(src).addEntry(new FileSource(fileName, newEntry)).destination(dest).process();
        assertTrue(ZipUtil.containsEntry(dest, fileName));
    }

    public void testRemoveEntry() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);

        File dest = File.createTempFile("temp", ".zip");
        try {
            Zips.get(src).removeEntry("bar.txt").destination(dest).process();
            assertTrue("Result zip misses entry 'foo.txt'", ZipUtil.containsEntry(dest, "foo.txt"));
            assertTrue("Result zip misses entry 'foo1.txt'", ZipUtil.containsEntry(dest, "foo1.txt"));
            assertTrue("Result zip misses entry 'foo2.txt'", ZipUtil.containsEntry(dest, "foo2.txt"));
            assertFalse("Result zip still contains 'bar.txt'", ZipUtil.containsEntry(dest, "bar.txt"));
        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testRemoveDirs() throws IOException {
        File src = new File("src/test/resources/demo-dirs.zip");

        File dest = File.createTempFile("temp", ".zip");
        try {
            Zips.get(src).removeEntries(new String[] { "bar.txt", "a/b" }).destination(dest).process();

            assertFalse("Result zip still contains 'bar.txt'", ZipUtil.containsEntry(dest, "bar.txt"));
            assertFalse("Result zip still contains dir 'a/b'", ZipUtil.containsEntry(dest, "a/b"));
            assertTrue("Result doesn't containt 'attic'", ZipUtil.containsEntry(dest, "attic/treasure.txt"));
            assertTrue("Entry whose prefix is dir name is removed too: 'b.txt'",
                    ZipUtil.containsEntry(dest, "a/b.txt"));
            assertFalse("Entry in a removed dir is still there: 'a/b/c.txt'",
                    ZipUtil.containsEntry(dest, "a/b/c.txt"));

        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testAddRemoveEntries() throws IOException {
        final String fileName = "TestFile.txt";
        File newEntry = new File("src/test/resources/" + fileName);

        File src = new File("src/test/resources/demo-dirs.zip");
        File dest = File.createTempFile("temp", ".zip");
        try {
            Zips.get(src).addEntry(new FileSource(fileName, newEntry))
                    .removeEntries(new String[] { "bar.txt", "a/b" }).destination(dest).process();

            assertFalse("Result zip still contains 'bar.txt'", ZipUtil.containsEntry(dest, "bar.txt"));
            assertFalse("Result zip still contains dir 'a/b'", ZipUtil.containsEntry(dest, "a/b"));
            assertTrue("Result doesn't containt 'attic'", ZipUtil.containsEntry(dest, "attic/treasure.txt"));
            assertTrue("Entry whose prefix is dir name is removed too: 'b.txt'",
                    ZipUtil.containsEntry(dest, "a/b.txt"));
            assertFalse("Entry in a removed dir is still there: 'a/b/c.txt'",
                    ZipUtil.containsEntry(dest, "a/b/c.txt"));
            assertTrue("Result doesn't contain added entry", ZipUtil.containsEntry(dest, fileName));

        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testInPlaceAddEntry() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);
        File dest = File.createTempFile("temp.zip", ".zip");
        try {
            FileUtils.copyFile(src, dest);

            final String fileName = "TestFile.txt";
            assertFalse(ZipUtil.containsEntry(dest, fileName));
            File newEntry = new File("src/test/resources/" + fileName);

            Zips.get(dest).addEntry(new FileSource(fileName, newEntry)).process();
            assertTrue(ZipUtil.containsEntry(dest, fileName));
        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testInPlaceAddRemoveEntries() throws IOException {
        final String fileName = "TestFile.txt";
        File newEntry = new File("src/test/resources/" + fileName);

        File original = new File("src/test/resources/demo-dirs.zip");
        File workFile = File.createTempFile("temp", ".zip");
        try {
            FileUtils.copyFile(original, workFile);
            Zips.get(workFile).addEntry(new FileSource(fileName, newEntry))
                    .removeEntries(new String[] { "bar.txt", "a/b" }).process();
            assertFalse("Result zip still contains 'bar.txt'", ZipUtil.containsEntry(workFile, "bar.txt"));
            assertFalse("Result zip still contains dir 'a/b'", ZipUtil.containsEntry(workFile, "a/b"));
            assertTrue("Result doesn't containt 'attic'", ZipUtil.containsEntry(workFile, "attic/treasure.txt"));
            assertTrue("Entry whose prefix is dir name is removed too: 'b.txt'",
                    ZipUtil.containsEntry(workFile, "a/b.txt"));
            assertFalse("Entry in a removed dir is still there: 'a/b/c.txt'",
                    ZipUtil.containsEntry(workFile, "a/b/c.txt"));
            assertTrue("Result doesn't contain added entry", ZipUtil.containsEntry(workFile, fileName));

        } finally {
            FileUtils.deleteQuietly(workFile);
        }
    }

    public void testPreservingTimestamps() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);

        File dest = File.createTempFile("temp", ".zip");
        final ZipFile zf = new ZipFile(src);
        try {
            Zips.get(src).addEntries(new ZipEntrySource[0]).preserveTimestamps().destination(dest).process();
            Zips.get(dest).iterate(new ZipEntryCallback() {
                public void process(InputStream in, ZipEntry zipEntry) throws IOException {
                    String name = zipEntry.getName();
                    assertEquals("Timestapms differ at entry " + name, zf.getEntry(name).getTime(),
                            zipEntry.getTime());
                }
            });
        } finally {
            ZipUtil.closeQuietly(zf);
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testPreservingTimestampsSetter() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);

        File dest = File.createTempFile("temp", ".zip");
        final ZipFile zf = new ZipFile(src);
        try {
            Zips.get(src).addEntries(new ZipEntrySource[0]).setPreserveTimestamps(true).destination(dest).process();
            Zips.get(dest).iterate(new ZipEntryCallback() {
                public void process(InputStream in, ZipEntry zipEntry) throws IOException {
                    String name = zipEntry.getName();
                    assertEquals("Timestapms differ at entry " + name, zf.getEntry(name).getTime(),
                            zipEntry.getTime());
                }
            });
        } finally {
            ZipUtil.closeQuietly(zf);
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testOverwritingTimestamps() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);

        File dest = File.createTempFile("temp", ".zip");
        final ZipFile zf = new ZipFile(src);
        try {
            Zips.get(src).addEntries(new ZipEntrySource[0]).destination(dest).process();
            Zips.get(dest).iterate(new ZipEntryCallback() {
                public void process(InputStream in, ZipEntry zipEntry) throws IOException {
                    String name = zipEntry.getName();
                    // original timestamp is believed to be earlier than test execution time.
                    assertTrue("Timestapms were carried over for entry " + name,
                            zf.getEntry(name).getTime() < zipEntry.getTime());
                }
            });
        } finally {
            ZipUtil.closeQuietly(zf);
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testAddRemovePriorities() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);
        String filename = "bar.txt";
        File newEntry = new File("src/test/resources/TestFile.txt");

        File dest = File.createTempFile("temp", ".zip");
        try {
            Zips.get(src).addEntry(new FileSource(filename, newEntry)).removeEntry(filename).destination(dest)
                    .process();
            assertTrue("Result zip misses entry 'foo.txt'", ZipUtil.containsEntry(dest, "foo.txt"));
            assertTrue("Result zip misses entry 'foo1.txt'", ZipUtil.containsEntry(dest, "foo1.txt"));
            assertTrue("Result zip misses entry 'foo2.txt'", ZipUtil.containsEntry(dest, "foo2.txt"));
            assertTrue("Result doesn't contain " + filename, ZipUtil.containsEntry(dest, filename));
            assertFalse(filename + " entry did not change", ZipUtil.entryEquals(src, dest, filename));
        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testCharsetEntry() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);
        final String fileName = "TestFile.txt";
        assertFalse(ZipUtil.containsEntry(src, fileName));

        File newEntry = new File("src/test/resources/TestFile.txt");
        File dest = File.createTempFile("temp.zip", ".zip");

        Charset charset = Charset.forName("UTF-8");
        String entryName = ".txt";
        try {
            Zips.get(src).charset(charset).addEntry(new FileSource(entryName, newEntry)).destination(dest)
                    .process();
        } catch (IllegalStateException e) {
            if (e.getMessage().startsWith("Using constructor ZipFile(File, Charset) has failed") || e.getMessage()
                    .startsWith("Using constructor ZipOutputStream(OutputStream, Charset) has failed")) {
                // this is acceptable when old java doesn't have charset constructor
                return;
            } else {
                System.out.println("'" + e.getMessage() + "'");
            }
        }

        ZipFile zf = null;
        try {
            zf = ZipFileUtil.getZipFile(dest, charset);
            assertNotNull("Entry '" + entryName + "' was not added", zf.getEntry(entryName));
        } finally {
            ZipUtil.closeQuietly(zf);
        }
    }

    public void testIterateAndBreak() {
        File src = new File("src/test/resources/demo.zip");
        final Set files = new HashSet();
        files.add("foo.txt");
        files.add("bar.txt");
        files.add("foo1.txt");
        files.add("foo2.txt");

        Zips.get(src).iterate(new ZipEntryCallback() {
            public void process(InputStream in, ZipEntry zipEntry) throws IOException {
                files.remove(zipEntry.getName());
                throw new ZipBreakException();
            }
        });
        assertEquals(3, files.size());
    }

    public void testAddEntryFile() throws Exception {
        File fileToPack = new File("src/test/resources/TestFile.txt");
        File dest = File.createTempFile("temp", ".zip");
        Zips.create().destination(dest).addFile(fileToPack).process();
        assertTrue(dest.exists());
        ZipUtil.explode(dest);
        assertTrue((new File(dest, "TestFile.txt")).exists());
        // if fails then maybe somebody changed the file contents and did not update
        // the test
        assertEquals(108, (new File(dest, "TestFile.txt")).length());
    }

    public void testAddEntryFilter() throws Exception {
        File fileToPack = new File("src/test/resources");
        File dest = File.createTempFile("temp", ".zip");
        FileFilter filter = new FileFilter() {
            public boolean accept(File pathname) {
                return FilenameUtils.getName(pathname.getAbsolutePath()).startsWith("TestFile");
            }
        };

        Zips.create().destination(dest).addFile(fileToPack, filter).process();
        assertTrue(dest.exists());
        assertTrue(ZipUtil.containsEntry(dest, "TestFile.txt"));
        assertTrue(ZipUtil.containsEntry(dest, "TestFile-II.txt"));
        assertFalse(ZipUtil.containsEntry(dest, "log4j.properties"));
    }

    public void testPackEntries() throws Exception {
        File fileToPack = new File("src/test/resources/TestFile.txt");
        File fileToPackII = new File("src/test/resources/TestFile-II.txt");
        File dest = File.createTempFile("temp", ".zip");
        Zips.create().destination(dest).addFile(fileToPack).addFile(fileToPackII).process();

        assertTrue(dest.exists());

        ZipUtil.explode(dest);
        assertTrue((new File(dest, "TestFile.txt")).exists());
        assertTrue((new File(dest, "TestFile-II.txt")).exists());
        // if fails then maybe somebody changed the file contents and did not update
        // the test
        assertEquals(108, (new File(dest, "TestFile.txt")).length());
        assertEquals(103, (new File(dest, "TestFile-II.txt")).length());
    }

    public void testPreserveRoot() throws Exception {
        File dest = File.createTempFile("temp", ".zip");
        File parent = new File("src/test/resources");
        // System.out.println("Parent file is " + parent);
        Zips.create().destination(dest).addFile(parent, true).process();
        ZipUtil.explode(dest);
        File parentDir = new File(dest, parent.getName());
        assertTrue("Root dir is not preserved", parentDir.exists());
        assertTrue("File from the parent directory was not added", new File(parentDir, "TestFile.txt").exists());
    }

    public void testPreserveRootWithSubdirectories() throws Exception {
        File dest = File.createTempFile("temp", ".zip");
        File parent = new File("src/test/resources/testDirectory");
        Zips.create().destination(dest).addFile(parent, true).process();
        String entryName = "testDirectory/testSubdirectory/testFileInTestSubdirectory.txt";
        assertContainsEntryWithSeparatorrs(dest, entryName, "/"); // this failed on windows
    }

    private void assertContainsEntryWithSeparatorrs(File zip, String entryPath, String expectedSeparator)
            throws IOException {
        char expectedSeparatorChar = expectedSeparator.charAt(0);
        String osSpecificEntryPath = entryPath.replace('\\', expectedSeparatorChar).replace('/',
                expectedSeparatorChar);
        ZipFile zf = new ZipFile(zip);
        try {
            if (zf.getEntry(osSpecificEntryPath) == null) {
                char unexpectedSeparatorChar = expectedSeparatorChar == '/' ? '\\' : '/';
                String nonOsSpecificEntryPath = entryPath.replace('\\', unexpectedSeparatorChar).replace('/',
                        unexpectedSeparatorChar);
                if (zf.getEntry(nonOsSpecificEntryPath) != null) {
                    fail(zip.getAbsolutePath() + " is not packed using directory separator '"
                            + expectedSeparatorChar + "', found entry '" + nonOsSpecificEntryPath + "', but not '"
                            + osSpecificEntryPath + "'"); // used to fail with this message on windows
                }
                StringBuilder sb = new StringBuilder();
                Enumeration entries = zf.entries();
                while (entries.hasMoreElements()) {
                    ZipEntry ze = (ZipEntry) entries.nextElement();
                    sb.append(ze.getName()).append(",");
                }
                fail(zip.getAbsolutePath() + " doesn't contain entry '" + entryPath
                        + "', but found following entries: " + sb.toString());
            }
        } finally {
            zf.close();
        }
        assertTrue("Didn't find entry '" + entryPath + "' from " + zip.getAbsolutePath(),
                ZipUtil.containsEntry(zip, entryPath));
    }

    public void testIgnoringRoot() throws Exception {
        File dest = File.createTempFile("temp", ".zip");
        File parent = new File("src/test/resources/TestFile.txt").getParentFile();
        // System.out.println("Parent file is " + parent);
        Zips.create().destination(dest).addFile(parent).process();
        ZipUtil.explode(dest);
        assertFalse("Root dir is preserved", (new File(dest, parent.getName())).exists());
        assertTrue("Child file is missing", (new File(dest, "TestFile.txt")).exists());
    }

    public void testByteArrayTransformer() throws IOException {
        final String name = "foo";
        final byte[] contents = "bar".getBytes();

        File source = File.createTempFile("temp", ".zip");
        File destination = File.createTempFile("temp", ".zip");
        try {
            // Create the ZIP file
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(source));
            try {
                zos.putNextEntry(new ZipEntry(name));
                zos.write(contents);
                zos.closeEntry();
            } finally {
                IOUtils.closeQuietly(zos);
            }

            // Transform the ZIP file
            ZipEntryTransformer transformer = new ByteArrayZipEntryTransformer() {
                protected byte[] transform(ZipEntry zipEntry, byte[] input) throws IOException {
                    String s = new String(input);
                    assertEquals(new String(contents), s);
                    return s.toUpperCase().getBytes();
                }
            };
            Zips.get(source).destination(destination).addTransformer(name, transformer).process();

            // Test the ZipUtil
            byte[] actual = ZipUtil.unpackEntry(destination, name);
            assertNotNull(actual);
            assertEquals(new String(contents).toUpperCase(), new String(actual));
        } finally {
            FileUtils.deleteQuietly(source);
            FileUtils.deleteQuietly(destination);
        }
    }

    public void testTransformationPreservesTimestamps() throws IOException {
        final String name = "foo";
        final byte[] contents = "bar".getBytes();

        File source = File.createTempFile("temp", ".zip");
        File destination = File.createTempFile("temp", ".zip");
        try {
            // Create the ZIP file
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(source));
            try {
                for (int i = 0; i < 2; i++) {
                    // we need many entries, some are transformed, some just copied.
                    ZipEntry e = new ZipEntry(name + (i == 0 ? "" : "" + i));
                    // 5 seconds ago.
                    e.setTime(System.currentTimeMillis() - 5000);
                    zos.putNextEntry(e);
                    zos.write(contents);
                    zos.closeEntry();
                }
            } finally {
                IOUtils.closeQuietly(zos);
            }
            // Transform the ZIP file
            ZipEntryTransformer transformer = new ByteArrayZipEntryTransformer() {
                protected byte[] transform(ZipEntry zipEntry, byte[] input) throws IOException {
                    String s = new String(input);
                    assertEquals(new String(contents), s);
                    return s.toUpperCase().getBytes();
                }

                protected boolean preserveTimestamps() {
                    // transformed entries preserve timestamps thanks to this.
                    return true;
                }
            };
            Zips.get(source).destination(destination).preserveTimestamps().addTransformer(name, transformer)
                    .process();

            final ZipFile zf = new ZipFile(source);
            try {
                Zips.get(destination).iterate(new ZipEntryCallback() {
                    public void process(InputStream in, ZipEntry zipEntry) throws IOException {
                        String name = zipEntry.getName();
                        assertEquals("Timestapms differ at entry " + name, zf.getEntry(name).getTime(),
                                zipEntry.getTime());
                    }
                });
            } finally {
                ZipUtil.closeQuietly(zf);
            }
            // Test the ZipUtil
            byte[] actual = ZipUtil.unpackEntry(destination, name);
            assertNotNull(actual);
            assertEquals(new String(contents).toUpperCase(), new String(actual));
        } finally {
            FileUtils.deleteQuietly(source);
            FileUtils.deleteQuietly(destination);
        }

    }

    public void testTransformAddedEntries() throws IOException {
        final String fileName = "TestFile.txt";
        File newEntry = new File("src/test/resources/" + fileName);

        File src = new File("src/test/resources/demo-dirs.zip");
        File dest = File.createTempFile("temp", ".zip");
        try {
            ZipEntryTransformer transformer = new ByteArrayZipEntryTransformer() {
                protected byte[] transform(ZipEntry zipEntry, byte[] input) throws IOException {
                    String s = new String(input);
                    return s.toUpperCase().getBytes();
                }

                protected boolean preserveTimestamps() {
                    // transformed entries preserve timestamps thanks to this.
                    return true;
                }
            };

            Zips.get(src).addEntry(new FileSource(fileName, newEntry)).addTransformer(fileName, transformer)
                    .destination(dest).process();

            assertTrue("Result doesn't containt 'attic'", ZipUtil.containsEntry(dest, "attic/treasure.txt"));
            assertTrue("Entry whose prefix is dir name is removed too: 'b.txt'",
                    ZipUtil.containsEntry(dest, "a/b.txt"));
            assertTrue("Result doesn't contain added entry", ZipUtil.containsEntry(dest, fileName));

            boolean contentIsUpper = new String(ZipUtil.unpackEntry(dest, fileName)).startsWith("I'M A TEST FILE");
            assertTrue("Added entry is not transformed!", contentIsUpper);

        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }

    public void testPackWithPrefixNameMapper() throws IOException {
        File fileToPack = new File("src/test/resources/TestFile.txt");
        File fileToPackII = new File("src/test/resources/TestFile-II.txt");
        File dest = File.createTempFile("temp", ".zip");
        Zips.create().destination(dest).nameMapper(new NameMapper() {
            public String map(String name) {
                return "doc/" + name;
            }
        }).addFile(fileToPack).addFile(fileToPackII).process();

        assertTrue(dest.exists());

        ZipUtil.explode(dest);
        assertTrue((new File(new File(dest, "doc"), "TestFile.txt")).exists());
        assertTrue((new File(new File(dest, "doc"), "TestFile-II.txt")).exists());
        // if fails then maybe somebody changed the file contents and did not update
        // the test
        assertEquals(108, (new File(new File(dest, "doc"), "TestFile.txt")).length());
        assertEquals(103, (new File(new File(dest, "doc"), "TestFile-II.txt")).length());
    }

    public void testPackWithSuffixOnlyNameMapper() throws IOException {
        File fileToPack = new File("src/test/resources/TestFile.txt");
        File fileToPackII = new File("src/test/resources/TestFile-II.txt");
        File dest = File.createTempFile("temp", ".zip");
        Zips.create().destination(dest).nameMapper(new NameMapper() {
            public String map(String name) {
                return name.endsWith("I.txt") ? name : null;
            }
        }).addFile(fileToPack).addFile(fileToPackII).process();

        assertTrue(dest.exists());

        ZipUtil.explode(dest);
        assertFalse((new File(dest, "TestFile.txt")).exists());
        assertTrue((new File(dest, "TestFile-II.txt")).exists());
        // if fails then maybe somebody changed the file contents and did not update
        // the test
        assertEquals(103, (new File(dest, "TestFile-II.txt")).length());
    }

    public void testUnpack() throws IOException {
        File src = new File(MainExamplesTest.DEMO_ZIP);

        final File dest = File.createTempFile("temp", null);

        Zips.get(src).unpack().destination(dest).process();
        assertTrue(dest.exists());
        ZipUtil.iterate(src, new ZipInfoCallback() {
            public void process(ZipEntry zipEntry) throws IOException {
                assertTrue(new File(dest, zipEntry.getName()).exists());
            }
        });
    }

    public void testUnpackInPlace() throws IOException {
        File original = new File(MainExamplesTest.DEMO_ZIP);
        final File src = File.createTempFile("temp", null);
        FileUtils.copyFile(original, src);
        Zips.get(src).unpack().process();
        assertTrue(src.isDirectory());
        ZipUtil.iterate(original, new ZipInfoCallback() {
            public void process(ZipEntry zipEntry) throws IOException {
                assertTrue(new File(src, zipEntry.getName()).exists());
            }
        });
    }

    public void testUnpackImplicit() throws IOException {
        File original = new File(MainExamplesTest.DEMO_ZIP);
        final File dest = File.createTempFile("temp", null);
        FileUtils.deleteQuietly(dest);
        dest.mkdirs();
        Zips.get(original).destination(dest).process();
        assertTrue(dest.isDirectory());
        ZipUtil.iterate(original, new ZipInfoCallback() {
            public void process(ZipEntry zipEntry) throws IOException {
                assertTrue(new File(dest, zipEntry.getName()).exists());
            }
        });
    }

    public void testUnpackWithTransofrmer() throws IOException {
        final String fileName = "TestFile.txt";
        File newEntry = new File("src/test/resources/" + fileName);

        File src = new File("src/test/resources/demo-dirs.zip");
        File dest = File.createTempFile("temp", ".zip");
        try {
            ZipEntryTransformer transformer = new ByteArrayZipEntryTransformer() {
                protected byte[] transform(ZipEntry zipEntry, byte[] input) throws IOException {
                    String s = new String(input);
                    byte[] result = s.toUpperCase().getBytes();
                    return result;
                }

                protected boolean preserveTimestamps() {
                    // transformed entries preserve timestamps thanks to this.
                    return true;
                }
            };

            Zips.get(src).unpack().addEntry(new FileSource(fileName, newEntry))
                    .addTransformer(fileName, transformer).destination(dest).process();
            assertTrue(dest.isDirectory());
            assertTrue("Result doesn't containt 'attic'", new File(dest, "attic/treasure.txt").exists());
            assertTrue("Result doesn't contain added entry", new File(dest, fileName).exists());

            boolean contentIsUpper = new String(FileUtils.readFileToString(new File(dest, fileName)))
                    .startsWith("I'M A TEST FILE");
            assertTrue("Added entry is not transformed!", contentIsUpper);
        } finally {
            FileUtils.deleteQuietly(dest);
        }
    }
}