package cz.cuni.mff.d3s.been.util;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class ZipUtilTest extends Assert {
private static final char SLASH = File.separatorChar;
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();
private Map<String, String> stringContents = new HashMap<>();
@Before
public void setUp() {
stringContents.put("root.xxx", "root example content");
stringContents.put("root" + SLASH + "subdir.xxx", "subdir1 example content");
stringContents.put("root" + SLASH + "subdir.xxx", "subdir2 example content");
stringContents.put("x" + SLASH + "x" + SLASH + "x" + SLASH + "x" + SLASH + "x" + SLASH + "x.xxx", "mega nested example content");
}
@Test
public void testZipStrings() throws Exception {
Collection<ItemToArchive> items = getExampleItemsCollection();
File outputFile = tmpFolder.newFile();
ZipUtil.createZip(items, outputFile);
Map<String, String> contents = readZipFileContents(outputFile);
assertMapsEqual(stringContents, contents);
}
@Test
public void testUnzipStrings() throws Exception {
final File archive = File.createTempFile(getClass().getSimpleName(), "zip");
final ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(archive)));
for(Map.Entry<String,String> entry: stringContents.entrySet()) {
zipStream.putNextEntry(new ZipArchiveEntry(entry.getKey()));
final byte [] bytes = entry.getValue().getBytes();
zipStream.write(bytes,0,bytes.length);
zipStream.closeEntry();
}
zipStream.close();
final File destDir = tmpFolder.newFolder();
ZipUtil.unzipToDir(archive, destDir);
assertFSContentCorrespondsWithMap(destDir, stringContents);
}
@Test
public void testPackUnpackEmptyFolder() throws IOException {
final File sourceFolder = tmpFolder.newFolder();
final File targetFolder = tmpFolder.newFolder();
final File archive = tmpFolder.newFile();
final File folderToPack = new File(sourceFolder, "folder");
folderToPack.mkdir();
final Collection<ItemToArchive> toPack = Arrays.asList((ItemToArchive) new FileToArchive("myFolder", folderToPack));
ZipUtil.createZip(toPack, archive);
ZipUtil.unzipToDir(archive, targetFolder);
final File expectedUnpackedFolder = new File(targetFolder, "myFolder");
assertTrue(expectedUnpackedFolder.exists());
assertTrue(expectedUnpackedFolder.isDirectory());
}
//---------------------------------------------------------
// SUPPORT METHODS
//---------------------------------------------------------
private void assertMapsEqual(Map<String, String> expected,
Map<String, String> actual) {
assertEquals(expected.size(), actual.size());
for (Entry<String, String> entry : expected.entrySet()) {
if (!actual.containsKey(entry.getKey())) {
fail(String.format("actual map does not contains key '%s'", entry.getKey()));
}
if (!actual.get(entry.getKey()).equals(entry.getValue())) {
fail("value differs for key '" + entry.getKey() + "' Expected '" + entry.getValue() + "', actual '" + actual.get(entry.getKey()) + "'");
}
}
}
private void assertFSContentCorrespondsWithMap(File rootDir, Map<String,String> expectedContent) throws IOException {
assertTrue(rootDir.exists() && rootDir.isDirectory());
for(Map.Entry<String,String> entry: expectedContent.entrySet()) {
final File expectedFile = new File(rootDir, entry.getKey());
assertTrue(expectedFile.exists());
if (expectedFile.isDirectory()) {
assertNull(entry.getValue()); // the only kind of entries we want to create dirs for are empty ones
} else {
assertEquals(entry.getValue(), FileUtils.readFileToString(expectedFile));
}
}
}
private Collection<ItemToArchive> getExampleItemsCollection() {
Collection<ItemToArchive> items = new ArrayList<>();
for (Entry<String, String> ex : stringContents.entrySet()) {
items.add(new StringToArchive(ex.getKey(), ex.getValue()));
}
return items;
}
private Map<String, String> readZipFileContents(File outputFile) throws FileNotFoundException, IOException {
Map<String, String> contents = new HashMap<>();
ZipInputStream zin = new ZipInputStream(new FileInputStream(outputFile));
ZipEntry ze;
while ((ze = zin.getNextEntry()) != null) {
if (!ze.isDirectory()) {
StringBuilder sb = new StringBuilder();
for (int c = zin.read(); c != -1; c = zin.read()) {
sb.append((char) c);
}
contents.put(ze.getName(), sb.toString());
zin.closeEntry();
}
}
zin.close();
return contents;
}
}