diff options
Diffstat (limited to 'src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java')
-rw-r--r-- | src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java new file mode 100644 index 0000000000..e58a90c923 --- /dev/null +++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java @@ -0,0 +1,373 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +package com.google.devtools.build.zip; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.primitives.Bytes; +import com.google.devtools.build.zip.ZipFileEntry.Compression; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Calendar; +import java.util.Random; +import java.util.zip.CRC32; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +@RunWith(JUnit4.class) +public class ZipWriterTest { + @Rule public TemporaryFolder tmp = new TemporaryFolder(); + @Rule public ExpectedException thrown = ExpectedException.none(); + + private Random rand; + private Calendar cal; + private CRC32 crc; + private Deflater deflater; + private File test; + + @Before public void setup() throws IOException { + rand = new Random(); + cal = Calendar.getInstance(); + cal.clear(); + cal.set(Calendar.YEAR, rand.nextInt(128) + 1980); // Zip files have 7-bit year resolution. + cal.set(Calendar.MONTH, rand.nextInt(12)); + cal.set(Calendar.DAY_OF_MONTH, rand.nextInt(29)); + cal.set(Calendar.HOUR_OF_DAY, rand.nextInt(24)); + cal.set(Calendar.MINUTE, rand.nextInt(60)); + cal.set(Calendar.SECOND, rand.nextInt(30) * 2); // Zip files have 2 second resolution. + + crc = new CRC32(); + deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); + test = tmp.newFile("test.zip"); + } + + @Test public void testEmpty() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + } + + try (ZipFile zipFile = new ZipFile(test)) { + assertThat(zipFile.entries().hasMoreElements()).isFalse(); + } + } + + @Test public void testComment() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + writer.setComment("test comment"); + } + + try (ZipFile zipFile = new ZipFile(test)) { + assertThat(zipFile.entries().hasMoreElements()).isFalse(); + assertThat(zipFile.getComment()).isEqualTo("test comment"); + } + } + + @Test public void testFileDataBeforeEntry() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + thrown.expect(ZipException.class); + thrown.expectMessage("Cannot write zip contents without first setting a ZipEntry or starting" + + " a prefix file."); + writer.write(new byte[] { 0xf, 0xa, 0xb }); + } + + try (ZipFile zipFile = new ZipFile(test)) { + assertThat(zipFile.entries().hasMoreElements()).isFalse(); + } + } + + @Test public void testSingleEntry() throws IOException { + ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8); + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(entry); + writer.write(content); + writer.closeEntry(); + writer.close(); + + byte[] buf = new byte[128]; + try (ZipFile zipFile = new ZipFile(test)) { + ZipEntry foo = zipFile.getEntry("foo"); + assertThat(foo.getMethod()).isEqualTo(ZipEntry.STORED); + assertThat(foo.getSize()).isEqualTo(content.length); + assertThat(foo.getCompressedSize()).isEqualTo(content.length); + assertThat(foo.getCrc()).isEqualTo(crc.getValue()); + assertThat(foo.getTime()).isEqualTo(cal.getTimeInMillis()); + zipFile.getInputStream(foo).read(buf); + assertThat(Bytes.indexOf(buf, content)).isEqualTo(0); + } + } + + @Test public void testMultipleEntry() throws IOException { + ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8); + writer.setComment("file comment"); + + byte[] fooContent = "content".getBytes(UTF_8); + crc.update(fooContent); + long fooCrc = crc.getValue(); + ZipFileEntry rawFoo = new ZipFileEntry("foo"); + rawFoo.setMethod(Compression.STORED); + rawFoo.setSize(fooContent.length); + rawFoo.setCompressedSize(fooContent.length); + rawFoo.setCrc(crc.getValue()); + rawFoo.setTime(cal.getTimeInMillis()); + rawFoo.setComment("foo comment"); + + writer.putNextEntry(rawFoo); + writer.write(fooContent); + writer.closeEntry(); + + byte[] barContent = "stuff".getBytes(UTF_8); + byte[] deflatedBarContent = new byte[128]; + crc.reset(); + crc.update(barContent); + long barCrc = crc.getValue(); + deflater.setInput(barContent); + deflater.finish(); + int deflatedSize = deflater.deflate(deflatedBarContent); + ZipFileEntry rawBar = new ZipFileEntry("bar"); + rawBar.setMethod(Compression.DEFLATED); + rawBar.setSize(barContent.length); + rawBar.setCompressedSize(deflatedSize); + rawBar.setCrc(barCrc); + rawBar.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(rawBar); + writer.write(deflatedBarContent, 0, deflatedSize); + writer.closeEntry(); + + writer.close(); + + byte[] buf = new byte[128]; + try (ZipFile zipFile = new ZipFile(test)) { + assertThat(zipFile.getComment()).isEqualTo("file comment"); + + ZipEntry foo = zipFile.getEntry("foo"); + assertThat(foo.getMethod()).isEqualTo(ZipEntry.STORED); + assertThat(foo.getSize()).isEqualTo(fooContent.length); + assertThat(foo.getCompressedSize()).isEqualTo(fooContent.length); + assertThat(foo.getCrc()).isEqualTo(fooCrc); + assertThat(foo.getTime()).isEqualTo(cal.getTimeInMillis()); + assertThat(foo.getComment()).isEqualTo("foo comment"); + zipFile.getInputStream(foo).read(buf); + assertThat(Bytes.indexOf(buf, fooContent)).isEqualTo(0); + + ZipEntry bar = zipFile.getEntry("bar"); + assertThat(bar.getMethod()).isEqualTo(ZipEntry.DEFLATED); + assertThat(bar.getSize()).isEqualTo(barContent.length); + assertThat(bar.getCompressedSize()).isEqualTo(deflatedSize); + assertThat(bar.getCrc()).isEqualTo(barCrc); + assertThat(bar.getTime()).isEqualTo(cal.getTimeInMillis()); + zipFile.getInputStream(bar).read(buf); + assertThat(Bytes.indexOf(buf, barContent)).isEqualTo(0); + } + } + + @Test public void testWrongSizeContent() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(entry); + writer.write("some other content".getBytes(UTF_8)); + thrown.expect(ZipException.class); + thrown.expectMessage("Number of bytes written for the entry"); + writer.closeEntry(); + } + } + + @Test public void testRawZipEntry() throws IOException { + ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8); + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setVersion((short) 1); + entry.setVersionNeeded((short) 2); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + entry.setFlags(ZipUtil.get16(new byte[]{ 0x08, 0x00 }, 0)); + entry.setInternalAttributes(ZipUtil.get16(new byte[]{ 0x34, 0x12 }, 0)); + entry.setExternalAttributes(ZipUtil.get32(new byte[]{ 0x0a, 0x09, 0x78, 0x56 }, 0)); + entry.setLocalHeaderOffset(rand.nextInt(Integer.MAX_VALUE)); + + writer.putNextEntry(entry); + writer.write(content); + writer.closeEntry(); + writer.close(); + + byte[] buf = new byte[128]; + try (ZipFile zipFile = new ZipFile(test)) { + ZipEntry foo = zipFile.getEntry("foo"); + assertThat(foo.getMethod()).isEqualTo(ZipEntry.STORED); + assertThat(foo.getSize()).isEqualTo(content.length); + assertThat(foo.getCompressedSize()).isEqualTo(content.length); + assertThat(foo.getCrc()).isEqualTo(crc.getValue()); + assertThat(foo.getTime()).isEqualTo(cal.getTimeInMillis()); + zipFile.getInputStream(foo).read(buf); + assertThat(Bytes.indexOf(buf, content)).isEqualTo(0); + } + + try (ZipReader zipFile = new ZipReader(test)) { + ZipFileEntry foo = zipFile.getEntry("foo"); + // Versions should be increased to minimum required for STORED compression. + assertThat(foo.getVersion()).isEqualTo((short) 0xa); + assertThat(foo.getVersionNeeded()).isEqualTo((short) 0xa); + assertThat(foo.getFlags()).isEqualTo((short) 0); // Data descriptor bit should be cleared. + assertThat(foo.getInternalAttributes()).isEqualTo((short) 4660); + assertThat(foo.getExternalAttributes()).isEqualTo(1450707210); + } + } + + @Test public void testPrefixFile() throws IOException, InterruptedException { + ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8); + + writer.startPrefixFile(); + writer.write("#!/bin/bash\necho 'hello world'\n".getBytes(UTF_8)); + writer.endPrefixFile(); + + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(entry); + writer.write(content); + writer.closeEntry(); + writer.close(); + + byte[] buf = new byte[128]; + try (ZipFile zipFile = new ZipFile(test)) { + ZipEntry foo = zipFile.getEntry("foo"); + assertThat(foo.getMethod()).isEqualTo(ZipEntry.STORED); + assertThat(foo.getSize()).isEqualTo(content.length); + assertThat(foo.getCompressedSize()).isEqualTo(content.length); + assertThat(foo.getCrc()).isEqualTo(crc.getValue()); + assertThat(foo.getTime()).isEqualTo(cal.getTimeInMillis()); + zipFile.getInputStream(foo).read(buf); + assertThat(Bytes.indexOf(buf, content)).isEqualTo(0); + } + + Process pr = new ProcessBuilder("chmod", "750", test.getAbsolutePath()).start(); + pr.waitFor(); + pr = new ProcessBuilder(test.getAbsolutePath()).start(); + pr.getInputStream().read(buf); + pr.waitFor(); + assertThat(Bytes.indexOf(buf, "hello world".getBytes(UTF_8))).isEqualTo(0); + } + + @Test public void testPrefixFileAfterZip() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(entry); + thrown.expect(ZipException.class); + thrown.expectMessage("Cannot add a prefix file after the zip contents have been started."); + writer.startPrefixFile(); + writer.write("#!/bin/bash\necho 'hello world'\n".getBytes(UTF_8)); + writer.endPrefixFile(); + } + } + + @Test public void testPrefixAfterFinish() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + writer.finish(); + thrown.expect(IllegalStateException.class); + writer.startPrefixFile(); + writer.write("#!/bin/bash\necho 'hello world'\n".getBytes(UTF_8)); + writer.endPrefixFile(); + } + } + + @Test public void testPutEntryAfterFinish() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + writer.finish(); + thrown.expect(IllegalStateException.class); + writer.putNextEntry(new ZipFileEntry("foo")); + } + } + + @Test public void testCloseEntryAfterFinish() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + byte[] content = "content".getBytes(UTF_8); + crc.update(content); + ZipFileEntry entry = new ZipFileEntry("foo"); + entry.setMethod(Compression.STORED); + entry.setSize(content.length); + entry.setCompressedSize(content.length); + entry.setCrc(crc.getValue()); + entry.setTime(cal.getTimeInMillis()); + + writer.putNextEntry(entry); + writer.write(content); + writer.finish(); + thrown.expect(IllegalStateException.class); + writer.closeEntry(); + } + } + + @Test public void testFinishAfterFinish() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + writer.finish(); + thrown.expect(IllegalStateException.class); + writer.finish(); + } + } + + @Test public void testWriteAfterFinish() throws IOException { + try (ZipWriter writer = new ZipWriter(new FileOutputStream(test), UTF_8)) { + writer.finish(); + thrown.expect(IllegalStateException.class); + writer.write("content".getBytes(UTF_8)); + } + } +} |