@Test public void testThatExternalAttributesFieldIsFunctional() throws IOException { // Prepare some sample modes to write into the zip file. final ImmutableList<String> samples = ImmutableList.of("rwxrwxrwx", "rw-r--r--", "--x--x--x", "---------"); for (String stringMode : samples) { long mode = MorePosixFilePermissions.toMode(PosixFilePermissions.fromString(stringMode)); // Write a tiny sample zip file, which sets the external attributes per the // permission sample above. try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING)) { CustomZipEntry entry = new CustomZipEntry("test"); entry.setTime(System.currentTimeMillis()); entry.setExternalAttributes(mode << 16); out.putNextEntry(entry); out.write(new byte[0]); } // Now re-read the zip file using apache's commons-compress, which supports parsing // the external attributes field. try (ZipFile in = new ZipFile(output.toFile())) { Enumeration<ZipArchiveEntry> entries = in.getEntries(); ZipArchiveEntry entry = entries.nextElement(); assertEquals(mode, entry.getExternalAttributes() >> 16); assertFalse(entries.hasMoreElements()); } } }
@Test(expected = ZipException.class) public void mustThrowAnExceptionIfNoZipEntryIsOpenWhenWritingData() throws IOException { try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output)) { // Note: we have not opened a zip entry. out.write("cheese".getBytes()); } }
@Test public void shouldSetTimestampOfEntries() throws IOException { Calendar cal = Calendar.getInstance(); cal.set(1999, SEPTEMBER, 10); long old = getTimeRoundedToSeconds(cal.getTime()); long now = getTimeRoundedToSeconds(new Date()); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output)) { ZipEntry oldAndValid = new ZipEntry("oldAndValid"); oldAndValid.setTime(old); out.putNextEntry(oldAndValid); ZipEntry current = new ZipEntry("current"); current.setTime(now); out.putNextEntry(current); } try (ZipInputStream in = new ZipInputStream(Files.newInputStream(output))) { ZipEntry entry = in.getNextEntry(); assertEquals("oldAndValid", entry.getName()); assertEquals(old, entry.getTime()); entry = in.getNextEntry(); assertEquals("current", entry.getName()); assertEquals(now, entry.getTime()); } }
@Test public void packingALargeFileShouldGenerateTheSameOutputWhenOverwritingAsWhenAppending() throws IOException { File reference = File.createTempFile("reference", ".zip"); String packageName = getClass().getPackage().getName().replace(".", "/"); URL sample = Resources.getResource(packageName + "/macbeth.properties"); byte[] input = Resources.toByteArray(sample); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING); ZipOutputStream ref = new ZipOutputStream(new FileOutputStream(reference))) { CustomZipEntry entry = new CustomZipEntry("macbeth.properties"); entry.setTime(System.currentTimeMillis()); out.putNextEntry(entry); ref.putNextEntry(entry); out.write(input); ref.write(input); } byte[] seen = Files.readAllBytes(output); byte[] expected = Files.readAllBytes(reference.toPath()); // Make sure the output is valid. try (ZipInputStream in = new ZipInputStream(Files.newInputStream(output))) { ZipEntry entry = in.getNextEntry(); assertEquals("macbeth.properties", entry.getName()); assertNull(in.getNextEntry()); } assertArrayEquals(expected, seen); }
@Override public int execute(ExecutionContext context) { File inputDirectory = inputDirectoryPath.toFile(); Preconditions.checkState( inputDirectory.exists() && inputDirectory.isDirectory(), "%s must be a directory.", inputDirectoryPath); try { ImmutableMap.Builder<File, ZipEntry> zipEntriesBuilder = ImmutableMap.builder(); addDirectoryToZipEntryList(inputDirectory, "", zipEntriesBuilder); ImmutableMap<File, ZipEntry> zipEntries = zipEntriesBuilder.build(); if (!zipEntries.isEmpty()) { try (CustomZipOutputStream outputStream = ZipOutputStreams.newOutputStream(outputZipPath.toFile())) { for (Map.Entry<File, ZipEntry> zipEntry : zipEntries.entrySet()) { outputStream.putNextEntry(zipEntry.getValue()); ByteStreams.copy(Files.newInputStreamSupplier(zipEntry.getKey()), outputStream); outputStream.closeEntry(); } } } } catch (IOException e) { e.printStackTrace(context.getStdErr()); return 1; } return 0; }
@Test(expected = ZipException.class) public void writingTheSameFileMoreThanOnceIsNormallyAnError() throws IOException { try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output)) { ZipEntry entry = new ZipEntry("example.txt"); out.putNextEntry(entry); out.putNextEntry(entry); } }
@Test public void shouldBeAbleToCreateEmptyArchiveWhenOverwriting() throws IOException { CustomZipOutputStream ignored = ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING); ignored.close(); try (Zip zip = new Zip(output, false)) { assertTrue(zip.getFileNames().isEmpty()); } }
@Test public void shouldBeAbleToCreateEmptyArchive() throws IOException { CustomZipOutputStream ignored = ZipOutputStreams.newOutputStream(output); ignored.close(); try (Zip zip = new Zip(output, /* forWriting */ false)) { assertTrue(zip.getFileNames().isEmpty()); } }
@Test public void canWriteContentToStoredZips() throws IOException { Path overwriteZip = Files.createTempFile("overwrite", ".zip"); byte[] input = "I like cheese".getBytes(UTF_8); try (CustomZipOutputStream overwrite = ZipOutputStreams.newOutputStream(overwriteZip, OVERWRITE_EXISTING); CustomZipOutputStream appending = ZipOutputStreams.newOutputStream(output, APPEND_TO_ZIP)) { CustomZipEntry entry = new CustomZipEntry("cheese.txt"); entry.setCompressionLevel(NO_COMPRESSION); entry.setTime(0); overwrite.putNextEntry(entry); appending.putNextEntry(entry); overwrite.write(input); appending.write(input); } }
@Test public void compressionCanBeSetOnAPerFileBasisAndIsHonoured() throws IOException { // Create some input that can be compressed. String packageName = getClass().getPackage().getName().replace(".", "/"); URL sample = Resources.getResource(packageName + "/sample-bytes.properties"); byte[] input = Resources.toByteArray(sample); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output)) { CustomZipEntry entry = new CustomZipEntry("default"); // Don't set the compression level. Should be the default. out.putNextEntry(entry); out.write(input); entry = new CustomZipEntry("stored"); entry.setCompressionLevel(NO_COMPRESSION); byte[] bytes = "stored".getBytes(); entry.setSize(bytes.length); entry.setCrc(Hashing.crc32().hashBytes(bytes).padToLong()); out.putNextEntry(entry); out.write(bytes); entry = new CustomZipEntry("best"); entry.setCompressionLevel(BEST_COMPRESSION); out.putNextEntry(entry); out.write(input); } try (ZipInputStream in = new ZipInputStream(Files.newInputStream(output))) { ZipEntry entry = in.getNextEntry(); assertEquals("default", entry.getName()); ByteStreams.copy(in, ByteStreams.nullOutputStream()); long defaultCompressedSize = entry.getCompressedSize(); assertNotEquals(entry.getCompressedSize(), entry.getSize()); entry = in.getNextEntry(); ByteStreams.copy(in, ByteStreams.nullOutputStream()); assertEquals("stored", entry.getName()); assertEquals(entry.getCompressedSize(), entry.getSize()); entry = in.getNextEntry(); ByteStreams.copy(in, ByteStreams.nullOutputStream()); assertEquals("best", entry.getName()); ByteStreams.copy(in, ByteStreams.nullOutputStream()); assertThat(entry.getCompressedSize(), lessThan(defaultCompressedSize)); } }
@Test public void shouldBeAbleToAddAZeroLengthFileWhenOverwriting() throws IOException { File reference = File.createTempFile("reference", ".zip"); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING); ZipOutputStream ref = new ZipOutputStream(new FileOutputStream(reference))) { ZipEntry entry = new ZipEntry("example.txt"); entry.setTime(System.currentTimeMillis()); out.putNextEntry(entry); ref.putNextEntry(entry); } byte[] seen = Files.readAllBytes(output); byte[] expected = Files.readAllBytes(reference.toPath()); assertArrayEquals(expected, seen); }
@Test public void writingTheSameFileMoreThanOnceWhenInAppendModeWritesItTwiceToTheZip() throws IOException { try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, APPEND_TO_ZIP)) { ZipEntry entry = new ZipEntry("example.txt"); out.putNextEntry(entry); out.write("cheese".getBytes()); out.putNextEntry(entry); out.write("cake".getBytes()); } List<String> names = Lists.newArrayList(); try (ZipInputStream in = new ZipInputStream(Files.newInputStream(output))) { for (ZipEntry entry = in.getNextEntry(); entry != null; entry = in.getNextEntry()) { names.add(entry.getName()); } } assertEquals(ImmutableList.of("example.txt", "example.txt"), names); }
@Test public void shouldBeAbleToAddASingleNonZeroLengthFile() throws IOException { File reference = File.createTempFile("reference", ".zip"); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output); ZipOutputStream ref = new ZipOutputStream(new FileOutputStream(reference))) { byte[] bytes = "cheese".getBytes(); ZipEntry entry = new ZipEntry("example.txt"); entry.setTime(System.currentTimeMillis()); out.putNextEntry(entry); ref.putNextEntry(entry); out.write(bytes); ref.write(bytes); } byte[] seen = Files.readAllBytes(output); byte[] expected = Files.readAllBytes(reference.toPath()); assertArrayEquals(expected, seen); }
@Test public void writingTheSameFileMoreThanOnceWhenInOverwriteModeWritesItOnceToTheZip() throws IOException { try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output, OVERWRITE_EXISTING)) { ZipEntry entry = new ZipEntry("example.txt"); out.putNextEntry(entry); out.write("cheese".getBytes()); out.putNextEntry(entry); out.write("cake".getBytes()); } List<String> names = Lists.newArrayList(); try (ZipInputStream in = new ZipInputStream(Files.newInputStream(output))) { for (ZipEntry entry = in.getNextEntry(); entry != null; entry = in.getNextEntry()) { assertEquals("example.txt", entry.getName()); names.add(entry.getName()); String out = CharStreams.toString(new InputStreamReader(in)); assertEquals("cake", out); } } assertEquals(1, names.size()); }
@Test public void shouldBeAbleToSimplyStoreInputFilesWithoutCompressing() throws IOException { File reference = File.createTempFile("reference", ".zip"); try (CustomZipOutputStream out = ZipOutputStreams.newOutputStream(output); ZipOutputStream ref = new ZipOutputStream(new FileOutputStream(reference))) { byte[] bytes = "cheese".getBytes(); ZipEntry entry = new ZipEntry("example.txt"); entry.setMethod(ZipEntry.STORED); entry.setTime(System.currentTimeMillis()); entry.setSize(bytes.length); entry.setCrc(Hashing.crc32().hashBytes(bytes).padToLong()); out.putNextEntry(entry); ref.putNextEntry(entry); out.write(bytes); ref.write(bytes); } byte[] seen = Files.readAllBytes(output); byte[] expected = Files.readAllBytes(reference.toPath()); assertArrayEquals(expected, seen); }