aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/java_tools/singlejar/javatests/com/google/devtools/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/java_tools/singlejar/javatests/com/google/devtools/build')
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java14
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java32
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java712
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipFileEntryTest.java193
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipReaderTest.java390
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipTests.java27
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipUtilTest.java172
-rw-r--r--src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipWriterTest.java373
8 files changed, 1461 insertions, 452 deletions
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java
index 8fec585fe0..d6f801f23e 100644
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java
@@ -21,10 +21,13 @@ import static org.junit.Assert.assertNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
@@ -74,6 +77,17 @@ public final class MockSimpleFileSystem implements SimpleFileSystem {
}
@Override
+ public File getFile(String filename) throws IOException {
+ byte[] data = files.get(filename);
+ if (data == null) {
+ throw new FileNotFoundException();
+ }
+ File file = File.createTempFile(filename, null);
+ Files.copy(new ByteArrayInputStream(data), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ return file;
+ }
+
+ @Override
public boolean delete(String filename) {
assertEquals(outputFileName, filename);
assertNotNull(out);
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java
index 0c67b61e18..34c4cc0bf5 100644
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java
@@ -14,8 +14,9 @@
package com.google.devtools.build.singlejar;
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
@@ -78,7 +79,7 @@ public class SingleJarTest {
private final List<String> manifestLines;
public ManifestValidator(List<String> manifestLines) {
- this.manifestLines = new ArrayList<String>(manifestLines);
+ this.manifestLines = new ArrayList<>(manifestLines);
Collections.sort(this.manifestLines);
}
@@ -146,7 +147,7 @@ public class SingleJarTest {
private void assertStripFirstLine(String expected, String testCase) {
byte[] result = SingleJar.stripFirstLine(testCase.getBytes(StandardCharsets.UTF_8));
- assertEquals(expected, new String(result));
+ assertEquals(expected, new String(result, UTF_8));
}
@Test
@@ -428,7 +429,7 @@ public class SingleJarTest {
MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
SingleJar singleJar = new SingleJar(mockFs);
- List<String> args = new ArrayList<String>();
+ List<String> args = new ArrayList<>();
args.add("--output");
args.add("output.jar");
args.addAll(infoPropertyArguments(buildInfo));
@@ -591,8 +592,8 @@ public class SingleJarTest {
singleJar.run(ImmutableList.of("--output", "output.jar", "--exclude_build_data",
"--resources", "a/b/c", "a/b/c"));
fail();
- } catch (IllegalStateException e) {
- assertTrue(e.getMessage().contains("already contains a file named a/b/c"));
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).contains("already contains a file named 'a/b/c'.");
}
}
@@ -616,19 +617,20 @@ public class SingleJarTest {
public void testCanAddPreamble() throws IOException {
MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
String preamble = "WeThePeople";
- mockFs.addFile(preamble, preamble.getBytes());
+ mockFs.addFile(preamble, preamble.getBytes(UTF_8));
SingleJar singleJar = new SingleJar(mockFs);
singleJar.run(ImmutableList.of("--output", "output.jar",
"--java_launcher", preamble,
"--main_class", "SomeClass"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addPreamble(preamble.getBytes())
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar",
- "Main-Class: SomeClass"))
- .addEntry("build-data.properties", redactedBuildData("output.jar", "SomeClass"));
+ FakeZipFile expectedResult =
+ new FakeZipFile()
+ .addPreamble(preamble.getBytes(UTF_8))
+ .addEntry("META-INF/", EXTRA_FOR_META_INF)
+ .addEntry(
+ JarFile.MANIFEST_NAME,
+ new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar",
+ "Main-Class: SomeClass"))
+ .addEntry("build-data.properties", redactedBuildData("output.jar", "SomeClass"));
expectedResult.assertSame(mockFs.toByteArray());
}
}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java
index e5345cb1f8..aba561bfd3 100644
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java
@@ -23,34 +23,44 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.devtools.build.singlejar.ZipCombiner.OutputMode;
import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
+import com.google.devtools.build.zip.ExtraData;
+import com.google.devtools.build.zip.ZipFileEntry;
+import com.google.devtools.build.zip.ZipReader;
+import com.google.devtools.build.zip.ZipUtil;
+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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Calendar;
+import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -59,39 +69,45 @@ import java.util.zip.ZipOutputStream;
*/
@RunWith(JUnit4.class)
public class ZipCombinerTest {
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+ @Rule public ExpectedException thrown = ExpectedException.none();
- private static final Date DOS_EPOCH = ZipCombiner.DOS_EPOCH;
-
- private InputStream sampleZip() {
+ private File sampleZip() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello.txt", "Hello World!");
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
}
- private InputStream sampleZip2() {
+ private File sampleZip2() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello2.txt", "Hello World 2!");
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
}
- private InputStream sampleZipWithTwoEntries() {
+ private File sampleZipWithTwoEntries() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello.txt", "Hello World!");
factory.addFile("hello2.txt", "Hello World 2!");
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
}
- private InputStream sampleZipWithOneUncompressedEntry() {
+ private File sampleZipWithOneUncompressedEntry() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello.txt", "Hello World!", false);
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
}
- private InputStream sampleZipWithTwoUncompressedEntries() {
+ private File sampleZipWithTwoUncompressedEntries() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello.txt", "Hello World!", false);
factory.addFile("hello2.txt", "Hello World 2!", false);
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
+ }
+
+ private File writeInputStreamToFile(InputStream in) throws IOException {
+ File out = tmp.newFile();
+ Files.copy(in, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ return out;
}
private void assertEntry(ZipInputStream zipInput, String filename, long time, byte[] content)
@@ -111,7 +127,7 @@ public class ZipCombinerTest {
private void assertEntry(ZipInputStream zipInput, String filename, byte[] content)
throws IOException {
- assertEntry(zipInput, filename, ZipCombiner.DOS_EPOCH.getTime(), content);
+ assertEntry(zipInput, filename, ZipUtil.DOS_EPOCH, content);
}
private void assertEntry(ZipInputStream zipInput, String filename, String content)
@@ -124,210 +140,112 @@ public class ZipCombinerTest {
assertEntry(zipInput, filename, date.getTime(), content.getBytes(ISO_8859_1));
}
- @Test
- public void testDateToDosTime() {
- assertEquals(0x210000, ZipCombiner.dateToDosTime(ZipCombiner.DOS_EPOCH));
- Calendar calendar = new GregorianCalendar();
- for (int i = 1980; i <= 2107; i++) {
- calendar.set(i, 0, 1, 0, 0, 0);
- int result = ZipCombiner.dateToDosTime(calendar.getTime());
- assertEquals(i - 1980, result >>> 25);
- assertEquals(1, (result >> 21) & 0xf);
- assertEquals(1, (result >> 16) & 0x1f);
- assertEquals(0, result & 0xffff);
- }
- }
-
- @Test
- public void testDateToDosTimeFailsForBadValues() {
- try {
- Calendar calendar = new GregorianCalendar();
- calendar.set(1979, 0, 1, 0, 0, 0);
- ZipCombiner.dateToDosTime(calendar.getTime());
- fail();
- } catch (IllegalArgumentException e) {
- /* Expected exception. */
- }
- try {
- Calendar calendar = new GregorianCalendar();
- calendar.set(2108, 0, 1, 0, 0, 0);
- ZipCombiner.dateToDosTime(calendar.getTime());
- fail();
- } catch (IllegalArgumentException e) {
- /* Expected exception. */
- }
- }
-
- @Test
- public void testCompressedDontCare() throws IOException {
+ @Test public void testCompressedDontCare() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZip());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", true);
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZip());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testCompressedForceDeflate() throws IOException {
+ @Test public void testCompressedForceDeflate() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(OutputMode.FORCE_DEFLATE, out);
- singleJar.addZip(sampleZip());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", true);
+ try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_DEFLATE, out)) {
+ zipCombiner.addZip(sampleZip());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testCompressedForceStored() throws IOException {
+ @Test public void testCompressedForceStored() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(OutputMode.FORCE_STORED, out);
- singleJar.addZip(sampleZip());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", false);
+ try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_STORED, out)) {
+ zipCombiner.addZip(sampleZip());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testUncompressedDontCare() throws IOException {
+ @Test public void testUncompressedDontCare() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZipWithOneUncompressedEntry());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", false);
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testUncompressedForceDeflate() throws IOException {
+ @Test public void testUncompressedForceDeflate() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(OutputMode.FORCE_DEFLATE, out);
- singleJar.addZip(sampleZipWithOneUncompressedEntry());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", true);
+ try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_DEFLATE, out)) {
+ zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testUncompressedForceStored() throws IOException {
+ @Test public void testUncompressedForceStored() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(OutputMode.FORCE_STORED, out);
- singleJar.addZip(sampleZipWithOneUncompressedEntry());
- singleJar.close();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("hello.txt", "Hello World!", false);
+ try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_STORED, out)) {
+ zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
+ }
+ FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
expectedResult.assertSame(out.toByteArray());
}
- @Test
- public void testCopyTwoEntries() throws IOException {
+ @Test public void testCopyTwoEntries() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testCopyTwoUncompressedEntries() throws IOException {
+ @Test public void testCopyTwoUncompressedEntries() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testCombine() throws IOException {
+ @Test public void testCombine() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZip2());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZip2());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testDuplicateEntry() throws IOException {
+ @Test public void testDuplicateEntry() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZip());
- singleJar.close();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertNull(zipInput.getNextEntry());
- }
-
- // Returns an input stream that can only read one byte at a time.
- private InputStream slowRead(final InputStream in) {
- return new InputStream() {
- @Override
- public int read() throws IOException {
- return in.read();
- }
- @Override
- public int read(byte b[], int off, int len) throws IOException {
- Preconditions.checkArgument(b != null);
- Preconditions.checkArgument((len >= 0) && (off >= 0));
- Preconditions.checkArgument(len <= b.length - off);
- if (len == 0) {
- return 0;
- }
- int value = read();
- if (value == -1) {
- return -1;
- }
- b[off] = (byte) value;
- return 1;
- }
- };
- }
-
- @Test
- public void testDuplicateUncompressedEntryWithSlowRead() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(slowRead(sampleZipWithOneUncompressedEntry()));
- singleJar.addZip(slowRead(sampleZipWithOneUncompressedEntry()));
- singleJar.close();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertNull(zipInput.getNextEntry());
- }
-
- @Test
- public void testDuplicateEntryWithSlowRead() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(slowRead(sampleZip()));
- singleJar.addZip(slowRead(sampleZip()));
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZip());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testBadZipFileNoEntry() throws IOException {
+ @Test public void testBadZipFileNoEntry() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ thrown.expect(ZipException.class);
+ thrown.expectMessage("It does not contain an end of central directory record.");
+ zipCombiner.addZip(writeInputStreamToFile(new ByteArrayInputStream(new byte[] {1, 2, 3, 4})));
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertNull(zipInput.getNextEntry());
}
@@ -336,24 +254,22 @@ public class ZipCombinerTest {
return new ByteArrayInputStream(content.getBytes(UTF_8));
}
- @Test
- public void testAddFile() throws IOException {
+ @Test public void testAddFile() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addFile("hello.txt", DOS_EPOCH, asStream("Hello World!"));
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addFile("hello.txt", ZipCombiner.DOS_EPOCH, asStream("Hello World!"));
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testAddFileAndDuplicateZipEntry() throws IOException {
+ @Test public void testAddFileAndDuplicateZipEntry() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addFile("hello.txt", DOS_EPOCH, asStream("Hello World!"));
- singleJar.addZip(sampleZip());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ zipCombiner.addFile("hello.txt", ZipCombiner.DOS_EPOCH, asStream("Hello World!"));
+ zipCombiner.addZip(sampleZip());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertNull(zipInput.getNextEntry());
@@ -381,7 +297,7 @@ public class ZipCombinerTest {
*/
class MockZipEntryFilter implements ZipEntryFilter {
- private Date date = DOS_EPOCH;
+ private Date date = ZipCombiner.DOS_EPOCH;
private final List<String> calls = new ArrayList<>();
// File name to merge strategy map.
private final Map<String, CustomMergeStrategy> behavior =
@@ -416,36 +332,33 @@ public class ZipCombinerTest {
}
}
- @Test
- public void testCopyCallsFilter() throws IOException {
+ @Test public void testCopyCallsFilter() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ }
assertEquals(Arrays.asList("hello.txt"), mockFilter.calls);
}
- @Test
- public void testDuplicateEntryCallsFilterOnce() throws IOException {
+ @Test public void testDuplicateEntryCallsFilterOnce() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZip());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZip());
+ }
assertEquals(Arrays.asList("hello.txt"), mockFilter.calls);
}
- @Test
- public void testMergeStrategy() throws IOException {
+ @Test public void testMergeStrategy() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -453,47 +366,29 @@ public class ZipCombinerTest {
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testMergeStrategyWithUncompressedFiles() throws IOException {
+ @Test public void testMergeStrategyWithUncompressedFiles() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.close();
- assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!\nHello World!");
- assertNull(zipInput.getNextEntry());
- }
-
- @Test
- public void testMergeStrategyWithUncompressedEntriesAndSlowRead() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(slowRead(sampleZipWithOneUncompressedEntry()));
- singleJar.addZip(slowRead(sampleZipWithTwoUncompressedEntries()));
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ }
assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
assertEntry(zipInput, "hello.txt", "Hello World!\nHello World!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testMergeStrategyWithSlowCopy() throws IOException {
+ @Test public void testMergeStrategyWithSlowCopy() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -501,44 +396,41 @@ public class ZipCombinerTest {
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testMergeStrategyWithUncompressedFilesAndSlowCopy() throws IOException {
+ @Test public void testMergeStrategyWithUncompressedFilesAndSlowCopy() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ }
assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!Hello World!");
assertNull(zipInput.getNextEntry());
}
- private InputStream specialZipWithMinusOne() {
+ private File specialZipWithMinusOne() throws IOException {
ZipFactory factory = new ZipFactory();
factory.addFile("hello.txt", new byte[] {-1});
- return factory.toInputStream();
+ return writeInputStreamToFile(factory.toInputStream());
}
- @Test
- public void testMergeStrategyWithSlowCopyAndNegativeBytes() throws IOException {
+ @Test public void testMergeStrategyWithSlowCopyAndNegativeBytes() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(specialZipWithMinusOne());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(specialZipWithMinusOne());
+ }
assertEquals(Arrays.asList("hello.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", new byte[] { -1 });
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testCopyDateHandling() throws IOException {
+ @Test public void testCopyDateHandling() throws IOException {
final Date date = new GregorianCalendar(2009, 8, 2, 0, 0, 0).getTime();
ZipEntryFilter mockFilter = new ZipEntryFilter() {
@Override
@@ -548,33 +440,31 @@ public class ZipCombinerTest {
}
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ }
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", date, "Hello World!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testMergeDateHandling() throws IOException {
+ @Test public void testMergeDateHandling() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
mockFilter.date = new GregorianCalendar(2009, 8, 2, 0, 0, 0).getTime();
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZip());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZip());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
assertEquals(Arrays.asList("hello.txt", "hello2.txt"), mockFilter.calls);
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello2.txt", DOS_EPOCH, "Hello World 2!");
+ assertEntry(zipInput, "hello2.txt", ZipCombiner.DOS_EPOCH, "Hello World 2!");
assertEntry(zipInput, "hello.txt", mockFilter.date, "Hello World!\nHello World!");
assertNull(zipInput.getNextEntry());
}
- @Test
- public void testDuplicateCallThrowsException() throws IOException {
+ @Test public void testDuplicateCallThrowsException() throws IOException {
ZipEntryFilter badFilter = new ZipEntryFilter() {
@Override
public void accept(String filename, StrategyCallback callback) throws IOException {
@@ -584,16 +474,15 @@ public class ZipCombinerTest {
}
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner singleJar = new ZipCombiner(badFilter, out)) {
- singleJar.addZip(sampleZip());
+ try (ZipCombiner zipCombiner = new ZipCombiner(badFilter, out)) {
+ zipCombiner.addZip(sampleZip());
fail();
} catch (IllegalStateException e) {
// Expected exception.
}
}
- @Test
- public void testNoCallThrowsException() throws IOException {
+ @Test public void testNoCallThrowsException() throws IOException {
ZipEntryFilter badFilter = new ZipEntryFilter() {
@Override
public void accept(String filename, StrategyCallback callback) {
@@ -601,8 +490,8 @@ public class ZipCombinerTest {
}
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner singleJar = new ZipCombiner(badFilter, out)) {
- singleJar.addZip(sampleZip());
+ try (ZipCombiner zipCombiner = new ZipCombiner(badFilter, out)) {
+ zipCombiner.addZip(sampleZip());
fail();
} catch (IllegalStateException e) {
// Expected exception.
@@ -612,20 +501,20 @@ public class ZipCombinerTest {
// This test verifies that if an entry A is renamed as A (identy mapping),
// then subsequent entries named A are still subject to filtering.
// Note: this is different from a copy, where subsequent entries are skipped.
- @Test
- public void testRenameIdentityMapping() throws IOException {
+ @Test public void testRenameIdentityMapping() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
mockFilter.renameMap.put("hello.txt", "hello.txt"); // identity rename, not copy
mockFilter.renameMap.put("hello2.txt", "hello2.txt"); // identity rename, not copy
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello2.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -634,20 +523,20 @@ public class ZipCombinerTest {
// This test verifies that multiple entries with the same name can be
// renamed to unique names.
- @Test
- public void testRenameNoConflictMapping() throws IOException {
+ @Test public void testRenameNoConflictMapping() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
mockFilter.renameMap.putAll("hello.txt", Arrays.asList("hello1.txt", "hello2.txt"));
mockFilter.renameMap.putAll("hello2.txt", Arrays.asList("world1.txt", "world2.txt"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello2.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello1.txt", "Hello World!");
assertEntry(zipInput, "world1.txt", "Hello World 2!");
@@ -659,8 +548,7 @@ public class ZipCombinerTest {
// This tests verifies that an attempt to rename an entry to a
// name already written, results in the entry being skipped, after
// calling the filter.
- @Test
- public void testRenameSkipUsedName() throws IOException {
+ @Test public void testRenameSkipUsedName() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
@@ -668,13 +556,15 @@ public class ZipCombinerTest {
Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
mockFilter.renameMap.put("hello2.txt", "hello2.txt");
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello2.txt", "hello.txt", "hello2.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly(
+ "hello.txt", "hello2.txt", "hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello1.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -685,21 +575,21 @@ public class ZipCombinerTest {
// This tests verifies that if an entry has been copied, then
// further entries of the same name are skipped (filter not invoked),
// and entries renamed to the same name are skipped (after calling filter).
- @Test
- public void testRenameAndCopy() throws IOException {
+ @Test public void testRenameAndCopy() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
mockFilter.renameMap.putAll("hello.txt",
Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello1.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -710,21 +600,21 @@ public class ZipCombinerTest {
// This tests verifies that if an entry has been skipped, then
// further entries of the same name are skipped (filter not invoked),
// and entries renamed to the same name are skipped (after calling filter).
- @Test
- public void testRenameAndSkip() throws IOException {
+ @Test public void testRenameAndSkip() throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
mockFilter.renameMap.putAll("hello.txt",
Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.addZip(sampleZipWithTwoEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ zipCombiner.addZip(sampleZipWithTwoEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello1.txt", "Hello World!");
assertEntry(zipInput, "hello3.txt", "Hello World!");
@@ -734,8 +624,7 @@ public class ZipCombinerTest {
// This test verifies that renaming works when input and output
// disagree on compression method. This is the simple case, where
// content is read and rewritten, and no header repair is needed.
- @Test
- public void testRenameWithUncompressedFiles () throws IOException {
+ @Test public void testRenameWithUncompressedFiles () throws IOException {
MockZipEntryFilter mockFilter = new MockZipEntryFilter();
mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
@@ -743,13 +632,15 @@ public class ZipCombinerTest {
Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
mockFilter.renameMap.put("hello2.txt", "hello2.txt");
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(mockFilter, out);
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.addZip(sampleZipWithTwoUncompressedEntries());
- singleJar.close();
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt",
- "hello.txt", "hello2.txt", "hello.txt", "hello2.txt").inOrder();
+ try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
+ }
+ assertThat(mockFilter.calls)
+ .containsExactly(
+ "hello.txt", "hello2.txt", "hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
+ .inOrder();
ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
assertEntry(zipInput, "hello1.txt", "Hello World!");
assertEntry(zipInput, "hello2.txt", "Hello World 2!");
@@ -762,66 +653,6 @@ public class ZipCombinerTest {
// the data descriptor marker. It's unfortunately a bit tricky to create such
// a ZIP.
private static final int LOCAL_FILE_HEADER_MARKER = 0x04034b50;
- private static final int DATA_DESCRIPTOR_MARKER = 0x08074b50;
- private static final byte[] DATA_DESCRIPTOR_MARKER_AS_BYTES = new byte[] {
- 0x50, 0x4b, 0x07, 0x08
- };
-
- // Create a ZIP with an data descriptor marker in the DEFLATE content of a
- // file. To do that, we build the ZIP byte by byte.
- private InputStream zipWithUnexpectedDataDescriptorMarker() {
- ByteBuffer out = ByteBuffer.wrap(new byte[200]).order(ByteOrder.LITTLE_ENDIAN);
- out.clear();
- // file header
- out.putInt(LOCAL_FILE_HEADER_MARKER); // file header signature
- out.putShort((short) 6); // version to extract
- out.putShort((short) 8); // general purpose bit flag
- out.putShort((short) ZipOutputStream.DEFLATED); // compression method
- out.putShort((short) 0); // mtime (00:00:00)
- out.putShort((short) 0x21); // mdate (1.1.1980)
- out.putInt(0); // crc32
- out.putInt(0); // compressed size
- out.putInt(0); // uncompressed size
- out.putShort((short) 1); // file name length
- out.putShort((short) 0); // extra field length
- out.put((byte) 'a'); // file name
-
- // file contents
- out.put((byte) 0x01); // deflated content block is last block and uncompressed
- out.putShort((short) 4); // uncompressed block length
- out.putShort((short) ~4); // negated uncompressed block length
- out.putInt(DATA_DESCRIPTOR_MARKER); // 4 bytes uncompressed data
-
- // data descriptor
- out.putInt(DATA_DESCRIPTOR_MARKER); // data descriptor with marker
- out.putInt((int) ZipFactory.calculateCrc32(DATA_DESCRIPTOR_MARKER_AS_BYTES));
- out.putInt(9);
- out.putInt(4);
- // We omit the central directory here. It's currently not used by
- // ZipCombiner or by java.util.zip.ZipInputStream, so that shouldn't be a
- // problem.
- return new ByteArrayInputStream(out.array());
- }
-
- // Check that the created ZIP is correct.
- @Test
- public void testZipWithUnexpectedDataDescriptorMarkerIsCorrect() throws IOException {
- ZipInputStream zipInput = new ZipInputStream(zipWithUnexpectedDataDescriptorMarker());
- assertEntry(zipInput, "a", DATA_DESCRIPTOR_MARKER_AS_BYTES);
- assertNull(zipInput.getNextEntry());
- }
-
- // Check that ZipCombiner handles the ZIP correctly.
- @Test
- public void testZipWithUnexpectedDataDescriptorMarker() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addZip(zipWithUnexpectedDataDescriptorMarker());
- singleJar.close();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "a", DATA_DESCRIPTOR_MARKER_AS_BYTES);
- assertNull(zipInput.getNextEntry());
- }
// Create a ZIP with a partial entry.
private InputStream zipWithPartialEntry() {
@@ -848,89 +679,96 @@ public class ZipCombinerTest {
return new ByteArrayInputStream(out.array());
}
- @Test
- public void testBadZipFilePartialEntry() throws IOException {
+ @Test public void testBadZipFilePartialEntry() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner singleJar = new ZipCombiner(out)) {
- singleJar.addZip(zipWithPartialEntry());
- fail();
- } catch (EOFException e) {
- // Expected exception.
+ try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
+ thrown.expect(ZipException.class);
+ thrown.expectMessage("It does not contain an end of central directory record.");
+ zipCombiner.addZip(writeInputStreamToFile(zipWithPartialEntry()));
}
}
- @Test
- public void testSimpleJarAgainstJavaUtil() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- JarOutputStream jarOut = new JarOutputStream(out);
- ZipEntry entry;
- entry = new ZipEntry("META-INF/");
- entry.setTime(DOS_EPOCH.getTime());
- entry.setMethod(JarOutputStream.STORED);
- entry.setSize(0);
- entry.setCompressedSize(0);
- entry.setCrc(0);
- jarOut.putNextEntry(entry);
- entry = new ZipEntry("META-INF/MANIFEST.MF");
- entry.setTime(DOS_EPOCH.getTime());
- entry.setMethod(JarOutputStream.DEFLATED);
- jarOut.putNextEntry(entry);
- jarOut.write(new byte[] { 1, 2, 3, 4 });
- jarOut.close();
- byte[] javaFile = out.toByteArray();
+ @Test public void testZipCombinerAgainstJavaUtil() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (JarOutputStream jarOut = new JarOutputStream(out)) {
+ ZipEntry entry;
+ entry = new ZipEntry("META-INF/");
+ entry.setTime(ZipCombiner.DOS_EPOCH.getTime());
+ entry.setMethod(JarOutputStream.STORED);
+ entry.setSize(0);
+ entry.setCompressedSize(0);
+ entry.setCrc(0);
+ jarOut.putNextEntry(entry);
+ entry = new ZipEntry("META-INF/MANIFEST.MF");
+ entry.setTime(ZipCombiner.DOS_EPOCH.getTime());
+ entry.setMethod(JarOutputStream.DEFLATED);
+ jarOut.putNextEntry(entry);
+ jarOut.write(new byte[] {1, 2, 3, 4});
+ }
+ File javaFile = writeInputStreamToFile(new ByteArrayInputStream(out.toByteArray()));
out.reset();
- ZipCombiner singleJar = new ZipCombiner(out);
- singleJar.addDirectory("META-INF/", DOS_EPOCH,
- new ExtraData[] { new ExtraData((short) 0xCAFE, new byte[0]) });
- singleJar.addFile("META-INF/MANIFEST.MF", DOS_EPOCH,
- new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
- singleJar.close();
- byte[] singlejarFile = out.toByteArray();
-
- new ZipTester(singlejarFile).validate();
- assertZipFilesEquivalent(singlejarFile, javaFile);
- }
-
- void assertZipFilesEquivalent(byte[] x, byte[] y) {
- assertEquals(x.length, y.length);
-
- for (int i = 0; i < x.length; i++) {
- if (x[i] != y[i]) {
- // Allow general purpose bit 11 (UTF-8 encoding) used in jdk7 to differ
- assertEquals("at position " + i, 0x08, x[i] ^ y[i]);
- // Check that x[i] is the second byte of a general purpose bit flag.
- // Phil Katz, you will never be forgotten.
- assertTrue(
- // Local header
- x[i-7] == 'P' && x[i-6] == 'K' && x[i-5] == 3 && x[i-4] == 4 ||
- // Central directory header
- x[i-9] == 'P' && x[i-8] == 'K' && x[i-7] == 1 && x[i-6] == 2);
- }
+ try (ZipCombiner zipcombiner = new ZipCombiner(out)) {
+ zipcombiner.addDirectory("META-INF/", ZipCombiner.DOS_EPOCH,
+ new ExtraData[] {new ExtraData((short) 0xCAFE, new byte[0])});
+ zipcombiner.addFile("META-INF/MANIFEST.MF", ZipCombiner.DOS_EPOCH,
+ new ByteArrayInputStream(new byte[] {1, 2, 3, 4}));
}
+ File zipCombinerFile = writeInputStreamToFile(new ByteArrayInputStream(out.toByteArray()));
+ byte[] zipCombinerRaw = out.toByteArray();
+
+ new ZipTester(zipCombinerRaw).validate();
+ assertZipFilesEquivalent(new ZipReader(zipCombinerFile), new ZipReader(javaFile));
+ }
+
+ void assertZipFilesEquivalent(ZipReader x, ZipReader y) {
+ Collection<ZipFileEntry> xEntries = x.entries();
+ Collection<ZipFileEntry> yEntries = y.entries();
+ assertThat(xEntries).hasSize(yEntries.size());
+ Iterator<ZipFileEntry> xIter = xEntries.iterator();
+ Iterator<ZipFileEntry> yIter = yEntries.iterator();
+ for (int i = 0; i < xEntries.size(); i++) {
+ assertZipEntryEquivalent(xIter.next(), yIter.next());
+ }
+ }
+
+ void assertZipEntryEquivalent(ZipFileEntry x, ZipFileEntry y) {
+ assertThat(x.getComment()).isEqualTo(y.getComment());
+ assertThat(x.getCompressedSize()).isEqualTo(y.getCompressedSize());
+ assertThat(x.getCrc()).isEqualTo(y.getCrc());
+ assertThat(x.getExternalAttributes()).isEqualTo(y.getExternalAttributes());
+ assertThat(x.getExtra()).isEqualTo(y.getExtra());
+ assertThat(x.getInternalAttributes()).isEqualTo(y.getInternalAttributes());
+ assertThat(x.getMethod()).isEqualTo(y.getMethod());
+ assertThat(x.getName()).isEqualTo(y.getName());
+ assertThat(x.getSize()).isEqualTo(y.getSize());
+ assertThat(x.getTime()).isEqualTo(y.getTime());
+ assertThat(x.getVersion()).isEqualTo(y.getVersion());
+ assertThat(x.getVersionNeeded()).isEqualTo(y.getVersionNeeded());
+ // Allow general purpose bit 3 (data descriptor) used in jdk7 to differ.
+ // Allow general purpose bit 11 (UTF-8 encoding) used in jdk7 to differ.
+ assertThat(x.getFlags() | (1 << 3) | (1 << 11))
+ .isEqualTo(y.getFlags() | (1 << 3) | (1 << 11));
}
/**
* Ensures that the code that grows the central directory and the code that patches it is not
* obviously broken.
*/
- @Test
- public void testLotsOfFiles() throws IOException {
+ @Test public void testLotsOfFiles() throws IOException {
int fileCount = 100;
- for (int blockSize : new int[] { 1, 2, 3, 4, 10, 1000 }) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipCombiner zipCombiner = new ZipCombiner(
- OutputMode.DONT_CARE, new CopyEntryFilter(), out, blockSize);
- for (int i = 0; i < fileCount; i++) {
- zipCombiner.addFile("hello" + i, DOS_EPOCH, asStream("Hello " + i + "!"));
- }
- zipCombiner.close();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (ZipCombiner zipCombiner =
+ new ZipCombiner(OutputMode.DONT_CARE, new CopyEntryFilter(), out)) {
for (int i = 0; i < fileCount; i++) {
- assertEntry(zipInput, "hello" + i, "Hello " + i + "!");
+ zipCombiner.addFile("hello" + i, ZipCombiner.DOS_EPOCH, asStream("Hello " + i + "!"));
}
- assertNull(zipInput.getNextEntry());
- new ZipTester(out.toByteArray()).validate();
}
+ ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
+ for (int i = 0; i < fileCount; i++) {
+ assertEntry(zipInput, "hello" + i, "Hello " + i + "!");
+ }
+ assertNull(zipInput.getNextEntry());
+ new ZipTester(out.toByteArray()).validate();
}
}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipFileEntryTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipFileEntryTest.java
new file mode 100644
index 0000000000..de05c4a6e8
--- /dev/null
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipFileEntryTest.java
@@ -0,0 +1,193 @@
+// 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 com.google.common.testing.NullPointerTester;
+import com.google.devtools.build.zip.ZipFileEntry.Compression;
+import com.google.devtools.build.zip.ZipFileEntry.Flag;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ZipFileEntryTest {
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test public void testNulls() {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicConstructors(ZipFileEntry.class);
+ tester.testAllPublicInstanceMethods(new ZipFileEntry("foo"));
+ }
+
+ @Test public void testCrc() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setCrc(32);
+ }
+
+ @Test public void testCrc_Negative() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry crc-32");
+ foo.setCrc(-1);
+ }
+
+ @Test public void testCrc_Large() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry crc-32");
+ foo.setCrc(0x100000000L);
+ }
+
+ @Test public void testSize() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setSize(32);
+ }
+
+ @Test public void testSize_Negative() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry size");
+ foo.setSize(-1);
+ }
+
+ @Test public void testSize_Large() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry size");
+ foo.setSize(0x100000000L);
+ }
+
+ @Test public void testCompressedSize() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setCompressedSize(32);
+ }
+
+ @Test public void testCompressedSize_Negative() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry size");
+ foo.setCompressedSize(-1);
+ }
+
+ @Test public void testCompressedSize_Large() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid entry size");
+ foo.setCompressedSize(0x100000000L);
+ }
+
+ @Test public void testMinVersion_MethodUpdated() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ assertThat(foo.getVersion()).isEqualTo((short) -1);
+ foo.setMethod(Compression.STORED);
+ assertThat(foo.getVersion()).isEqualTo((short) 0x0a);
+ }
+
+ @Test public void testMinVersion_Update() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setMethod(Compression.STORED);
+ foo.setVersion((short) 0x14);
+ assertThat(foo.getVersion()).isEqualTo((short) 0x14);
+ }
+
+ @Test public void testMinVersion_BelowRequired() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setMethod(Compression.STORED);
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("The minimum allowable version for method STORED is 0x0a.");
+ foo.setVersion((short) 0);
+ }
+
+ @Test public void testMinVersionNeeded_MethodUpdated() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ assertThat(foo.getVersionNeeded()).isEqualTo((short) -1);
+ foo.setMethod(Compression.DEFLATED);
+ assertThat(foo.getVersionNeeded()).isEqualTo((short) 0x14);
+ }
+
+ @Test public void testMinVersionNeeded_Update() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setMethod(Compression.STORED);
+ foo.setVersionNeeded((short) 0x28);
+ assertThat(foo.getVersionNeeded()).isEqualTo((short) 0x28);
+ }
+
+ @Test public void testMinVersionNeeded_BelowRequired() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setMethod(Compression.DEFLATED);
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("The minimum allowable version for method DEFLATED is 0x14.");
+ foo.setVersionNeeded((short) 0x0a);
+ }
+
+ @Test public void testSetFlag() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setFlag(Flag.DATA_DESCRIPTOR, true);
+ assertThat(foo.getFlags()).isEqualTo((short) 0x08);
+ foo.setFlag(Flag.DATA_DESCRIPTOR, true);
+ assertThat(foo.getFlags()).isEqualTo((short) 0x08);
+ foo.setFlag(Flag.DATA_DESCRIPTOR, false);
+ assertThat(foo.getFlags()).isEqualTo((short) 0x00);
+ foo.setFlag(Flag.DATA_DESCRIPTOR, false);
+ assertThat(foo.getFlags()).isEqualTo((short) 0x00);
+ }
+
+ @Test public void testLocalHeaderOffset() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setLocalHeaderOffset(32);
+ }
+
+ @Test public void testLocalHeaderOffset_Negative() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid local header offset");
+ foo.setLocalHeaderOffset(-1);
+ }
+
+ @Test public void testLocalHeaderOffset_Large() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid local header offset");
+ foo.setLocalHeaderOffset(0x100000000L);
+ }
+
+ @Test public void testExtra() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ foo.setExtra(new byte[32]);
+ }
+
+ @Test public void testExtra_Large() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("invalid extra field length");
+ foo.setExtra(new byte[0x10000]);
+ }
+
+ @Test public void testExtraData() {
+ ZipFileEntry foo = new ZipFileEntry("foo");
+ ExtraData[] extra = new ExtraData[] {
+ new ExtraData((short) 0xCAFE, new byte[] { 0x01, 0x02 }),
+ new ExtraData((short) 0xADDE, new byte[] { (byte) 0xBE, (byte) 0xEF }) };
+ foo.setExtra(extra);
+ assertThat(foo.getExtra()).isEqualTo(new byte[] {
+ (byte) 0xFE, (byte) 0xCA, 0x02, 0x00, 0x01, 0x02,
+ (byte) 0xDE, (byte) 0xAD, 0x02, 0x00, (byte) 0xBE, (byte) 0xEF });
+ }
+}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipReaderTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipReaderTest.java
new file mode 100644
index 0000000000..67346932d3
--- /dev/null
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipReaderTest.java
@@ -0,0 +1,390 @@
+// 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 static org.junit.Assert.fail;
+
+import com.google.devtools.build.zip.ZipFileEntry.Compression;
+
+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.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipOutputStream;
+
+@RunWith(JUnit4.class)
+public class ZipReaderTest {
+ private void assertDateWithin(Date testDate, Date start, Date end) {
+ if (testDate.before(start) || testDate.after(end)) {
+ fail();
+ }
+ }
+
+ private void assertDateAboutNow(Date testDate) {
+ Date now = new Date();
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(now);
+ cal.add(Calendar.MINUTE, -30);
+ Date start = cal.getTime();
+ cal.add(Calendar.HOUR, 1);
+ Date end = cal.getTime();
+ assertDateWithin(testDate, start, end);
+ }
+
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test public void testMalformed_Empty() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (FileOutputStream out = new FileOutputStream(test)) {
+ }
+ thrown.expect(ZipException.class);
+ thrown.expectMessage("is malformed. It does not contain an end of central directory record.");
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ }
+ }
+
+ @Test public void testMalformed_ShorterThanSignature() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (FileOutputStream out = new FileOutputStream(test)) {
+ out.write(new byte[] { 1, 2, 3 });
+ }
+ thrown.expect(ZipException.class);
+ thrown.expectMessage("is malformed. It does not contain an end of central directory record.");
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ }
+ }
+
+ @Test public void testMalformed_SignatureLength() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (FileOutputStream out = new FileOutputStream(test)) {
+ out.write(new byte[] { 1, 2, 3, 4 });
+ }
+ thrown.expect(ZipException.class);
+ thrown.expectMessage("is malformed. It does not contain an end of central directory record.");
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ }
+ }
+
+ @Test public void testEmpty() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ }
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ assertThat(reader.entries()).isEmpty();
+ }
+ }
+
+ @Test public void testFileComment() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ zout.setComment("test comment");
+ }
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ assertThat(reader.entries()).isEmpty();
+ assertThat(reader.getComment()).isEqualTo("test comment");
+ }
+ }
+
+ @Test public void testFileCommentWithSignature() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ zout.setComment("test comment\u0050\u004b\u0005\u0006abcdefghijklmnopqrstuvwxyz");
+ }
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ assertThat(reader.entries()).isEmpty();
+ assertThat(reader.getComment())
+ .isEqualTo("test comment\u0050\u004b\u0005\u0006abcdefghijklmnopqrstuvwxyz");
+ }
+ }
+
+ @Test public void testSingleEntry() throws IOException {
+ File test = tmp.newFile("test.zip");
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ zout.putNextEntry(new ZipEntry("test"));
+ zout.write("foo".getBytes(UTF_8));
+ zout.closeEntry();
+ }
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ assertThat(reader.entries()).hasSize(1);
+ }
+ }
+
+ @Test public void testMultipleEntries() throws IOException {
+ File test = tmp.newFile("test.zip");
+ String[] names = new String[] { "test", "foo", "bar", "baz" };
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ for (String name : names) {
+ zout.putNextEntry(new ZipEntry(name));
+ zout.write(name.getBytes(UTF_8));
+ zout.closeEntry();
+ }
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ assertThat(reader.entries()).hasSize(names.length);
+ int i = 0;
+ for (ZipFileEntry entry : reader.entries()) {
+ assertThat(entry.getName()).isEqualTo(names[i++]);
+ }
+ assertThat(i).isEqualTo(names.length);
+ }
+ }
+
+ @Test public void testZipEntryFields() throws IOException {
+ File test = tmp.newFile("test.zip");
+ CRC32 crc = new CRC32();
+ Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
+ long date = 791784306000L; // 2/3/1995 04:05:06
+ byte[] extra = new byte[] { (byte) 0xaa, (byte) 0xbb, (byte) 0xcd };
+ byte[] tmp = new byte[128];
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+
+ ZipEntry foo = new ZipEntry("foo");
+ foo.setComment("foo comment.");
+ foo.setMethod(ZipEntry.DEFLATED);
+ foo.setTime(date);
+ foo.setExtra(extra);
+ zout.putNextEntry(foo);
+ zout.write("foo".getBytes(UTF_8));
+ zout.closeEntry();
+
+ ZipEntry bar = new ZipEntry("bar");
+ bar.setComment("bar comment.");
+ bar.setMethod(ZipEntry.STORED);
+ bar.setSize("bar".length());
+ bar.setCompressedSize("bar".length());
+ crc.reset();
+ crc.update("bar".getBytes(UTF_8));
+ bar.setCrc(crc.getValue());
+ zout.putNextEntry(bar);
+ zout.write("bar".getBytes(UTF_8));
+ zout.closeEntry();
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ ZipFileEntry fooEntry = reader.getEntry("foo");
+ assertThat(fooEntry.getName()).isEqualTo("foo");
+ assertThat(fooEntry.getComment()).isEqualTo("foo comment.");
+ assertThat(fooEntry.getMethod()).isEqualTo(Compression.DEFLATED);
+ assertThat(fooEntry.getVersion()).isEqualTo(Compression.DEFLATED.getMinVersion());
+ assertThat(fooEntry.getTime()).isEqualTo(date);
+ assertThat(fooEntry.getSize()).isEqualTo("foo".length());
+ deflater.reset();
+ deflater.setInput("foo".getBytes(UTF_8));
+ deflater.finish();
+ assertThat(fooEntry.getCompressedSize()).isEqualTo(deflater.deflate(tmp));
+ crc.reset();
+ crc.update("foo".getBytes(UTF_8));
+ assertThat(fooEntry.getCrc()).isEqualTo(crc.getValue());
+ assertThat(fooEntry.getExtra()).isEqualTo(extra);
+
+ ZipFileEntry barEntry = reader.getEntry("bar");
+ assertThat(barEntry.getName()).isEqualTo("bar");
+ assertThat(barEntry.getComment()).isEqualTo("bar comment.");
+ assertThat(barEntry.getMethod()).isEqualTo(Compression.STORED);
+ assertThat(barEntry.getVersion()).isEqualTo(Compression.STORED.getMinVersion());
+ assertDateAboutNow(new Date(barEntry.getTime()));
+ assertThat(barEntry.getSize()).isEqualTo("bar".length());
+ assertThat(barEntry.getCompressedSize()).isEqualTo("bar".length());
+ crc.reset();
+ crc.update("bar".getBytes(UTF_8));
+ assertThat(barEntry.getCrc()).isEqualTo(crc.getValue());
+ assertThat(barEntry.getExtra()).isEqualTo(new byte[] {});
+ }
+ }
+
+ @Test public void testZipEntryInvalidTime() throws IOException {
+ File test = tmp.newFile("test.zip");
+ long date = 312796800000L; // 11/30/1979 00:00:00, which is also 0 in DOS format
+ byte[] extra = new byte[] { (byte) 0xaa, (byte) 0xbb, (byte) 0xcd };
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ ZipEntry foo = new ZipEntry("foo");
+ foo.setComment("foo comment.");
+ foo.setMethod(ZipEntry.DEFLATED);
+ foo.setTime(date);
+ foo.setExtra(extra);
+ zout.putNextEntry(foo);
+ zout.write("foo".getBytes(UTF_8));
+ zout.closeEntry();
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ ZipFileEntry fooEntry = reader.getEntry("foo");
+ assertThat(fooEntry.getTime()).isEqualTo(ZipUtil.DOS_EPOCH);
+ }
+ }
+
+ @Test public void testRawFileData() throws IOException {
+ File test = tmp.newFile("test.zip");
+ CRC32 crc = new CRC32();
+ Deflater deflator = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ ZipEntry foo = new ZipEntry("foo");
+ foo.setComment("foo comment.");
+ foo.setMethod(ZipEntry.DEFLATED);
+ zout.putNextEntry(foo);
+ zout.write("foo".getBytes(UTF_8));
+ zout.closeEntry();
+
+ ZipEntry bar = new ZipEntry("bar");
+ bar.setComment("bar comment.");
+ bar.setMethod(ZipEntry.STORED);
+ bar.setSize("bar".length());
+ bar.setCompressedSize("bar".length());
+ crc.reset();
+ crc.update("bar".getBytes(UTF_8));
+ bar.setCrc(crc.getValue());
+ zout.putNextEntry(bar);
+ zout.write("bar".getBytes(UTF_8));
+ zout.closeEntry();
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ ZipFileEntry fooEntry = reader.getEntry("foo");
+ InputStream fooIn = reader.getRawInputStream(fooEntry);
+ byte[] fooData = new byte[10];
+ fooIn.read(fooData);
+ byte[] expectedFooData = new byte[10];
+ deflator.reset();
+ deflator.setInput("foo".getBytes(UTF_8));
+ deflator.finish();
+ deflator.deflate(expectedFooData);
+ assertThat(fooData).isEqualTo(expectedFooData);
+
+ ZipFileEntry barEntry = reader.getEntry("bar");
+ InputStream barIn = reader.getRawInputStream(barEntry);
+ byte[] barData = new byte[3];
+ barIn.read(barData);
+ byte[] expectedBarData = "bar".getBytes(UTF_8);
+ assertThat(barData).isEqualTo(expectedBarData);
+
+ assertThat(barIn.read()).isEqualTo(-1);
+ assertThat(barIn.read(barData)).isEqualTo(-1);
+ assertThat(barIn.read(barData, 0, 3)).isEqualTo(-1);
+
+ thrown.expect(IOException.class);
+ thrown.expectMessage("Reset is not supported on this type of stream.");
+ barIn.reset();
+ }
+ }
+
+ @Test public void testFileData() throws IOException {
+ File test = tmp.newFile("test.zip");
+ CRC32 crc = new CRC32();
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ ZipEntry foo = new ZipEntry("foo");
+ foo.setComment("foo comment.");
+ foo.setMethod(ZipEntry.DEFLATED);
+ zout.putNextEntry(foo);
+ zout.write("foo".getBytes(UTF_8));
+ zout.closeEntry();
+
+ ZipEntry bar = new ZipEntry("bar");
+ bar.setComment("bar comment.");
+ bar.setMethod(ZipEntry.STORED);
+ bar.setSize("bar".length());
+ bar.setCompressedSize("bar".length());
+ crc.reset();
+ crc.update("bar".getBytes(UTF_8));
+ bar.setCrc(crc.getValue());
+ zout.putNextEntry(bar);
+ zout.write("bar".getBytes(UTF_8));
+ zout.closeEntry();
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ ZipFileEntry fooEntry = reader.getEntry("foo");
+ InputStream fooIn = reader.getInputStream(fooEntry);
+ byte[] fooData = new byte[3];
+ fooIn.read(fooData);
+ byte[] expectedFooData = "foo".getBytes(UTF_8);
+ assertThat(fooData).isEqualTo(expectedFooData);
+
+ assertThat(fooIn.read()).isEqualTo(-1);
+ assertThat(fooIn.read(fooData)).isEqualTo(-1);
+ assertThat(fooIn.read(fooData, 0, 3)).isEqualTo(-1);
+
+ ZipFileEntry barEntry = reader.getEntry("bar");
+ InputStream barIn = reader.getInputStream(barEntry);
+ byte[] barData = new byte[3];
+ barIn.read(barData);
+ byte[] expectedBarData = "bar".getBytes(UTF_8);
+ assertThat(barData).isEqualTo(expectedBarData);
+
+ assertThat(barIn.read()).isEqualTo(-1);
+ assertThat(barIn.read(barData)).isEqualTo(-1);
+ assertThat(barIn.read(barData, 0, 3)).isEqualTo(-1);
+
+ thrown.expect(IOException.class);
+ thrown.expectMessage("Reset is not supported on this type of stream.");
+ barIn.reset();
+ }
+ }
+
+ @Test public void testSimultaneousReads() throws IOException {
+ File test = tmp.newFile("test.zip");
+ byte[] expectedFooData = "This if file foo. It contains a foo.".getBytes(UTF_8);
+ byte[] expectedBarData = "This is a different file bar. It contains only a bar."
+ .getBytes(UTF_8);
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(test))) {
+ ZipEntry foo = new ZipEntry("foo");
+ foo.setComment("foo comment.");
+ foo.setMethod(ZipEntry.DEFLATED);
+ zout.putNextEntry(foo);
+ zout.write(expectedFooData);
+ zout.closeEntry();
+
+ ZipEntry bar = new ZipEntry("bar");
+ bar.setComment("bar comment.");
+ bar.setMethod(ZipEntry.DEFLATED);
+ zout.putNextEntry(bar);
+ zout.write(expectedBarData);
+ zout.closeEntry();
+ }
+
+ try (ZipReader reader = new ZipReader(test, UTF_8)) {
+ ZipFileEntry fooEntry = reader.getEntry("foo");
+ ZipFileEntry barEntry = reader.getEntry("bar");
+ InputStream fooIn = reader.getInputStream(fooEntry);
+ InputStream barIn = reader.getInputStream(barEntry);
+ byte[] fooData = new byte[expectedFooData.length];
+ byte[] barData = new byte[expectedBarData.length];
+ fooIn.read(fooData, 0, 10);
+ barIn.read(barData, 0, 10);
+ fooIn.read(fooData, 10, 10);
+ barIn.read(barData, 10, 10);
+ fooIn.read(fooData, 20, fooData.length - 20);
+ barIn.read(barData, 20, barData.length - 20);
+ assertThat(fooData).isEqualTo(expectedFooData);
+ assertThat(barData).isEqualTo(expectedBarData);
+ }
+ }
+}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipTests.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipTests.java
new file mode 100644
index 0000000000..2b05b5c2a5
--- /dev/null
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipTests.java
@@ -0,0 +1,27 @@
+// 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 com.google.devtools.build.lib.testutil.ClasspathSuite;
+
+import org.junit.runner.RunWith;
+
+/**
+ * A test-suite builder for this package.
+ */
+@RunWith(ClasspathSuite.class)
+public class ZipTests {
+}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipUtilTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipUtilTest.java
new file mode 100644
index 0000000000..60f2b732c7
--- /dev/null
+++ b/src/java_tools/singlejar/javatests/com/google/devtools/build/zip/ZipUtilTest.java
@@ -0,0 +1,172 @@
+// 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@RunWith(JUnit4.class)
+public class ZipUtilTest {
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test public void testShortToLittleEndian() {
+ byte[] bytes = ZipUtil.shortToLittleEndian((short) 4660);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x34, 0x12 });
+ }
+
+ @Test public void testShortToLittleEndian_Signed() {
+ byte[] bytes = ZipUtil.shortToLittleEndian((short) -3532);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x34, (byte) 0xf2 });
+ }
+
+ @Test public void testIntToLittleEndian() {
+ byte[] bytes = ZipUtil.intToLittleEndian(305419896);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x78, 0x56, 0x34, 0x12 });
+ }
+
+ @Test public void testIntToLittleEndian_Signed() {
+ byte[] bytes = ZipUtil.intToLittleEndian(-231451016);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x78, 0x56, 0x34, (byte) 0xf2 });
+ }
+
+ @Test public void testLongToLittleEndian() {
+ byte[] bytes = ZipUtil.longToLittleEndian(305419896);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0 });
+ }
+
+ @Test public void testLongToLittleEndian_Signed() {
+ byte[] bytes = ZipUtil.longToLittleEndian(-231451016);
+ assertThat(bytes).isEqualTo(new byte[]{ 0x78, 0x56, 0x34, (byte) 0xf2,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff });
+ }
+
+ @Test public void testGet16() {
+ short result = ZipUtil.get16(new byte[]{ 0x34, 0x12 }, 0);
+ assertThat(result).isEqualTo((short) 0x1234);
+ assertThat(result).isEqualTo((short) 4660);
+ }
+
+ @Test public void testGet16_Signed() {
+ short result = ZipUtil.get16(new byte[]{ 0x34, (byte) 0xff }, 0);
+ assertThat(result).isEqualTo((short) 0xff34);
+ assertThat(result).isEqualTo((short) -204);
+ }
+
+ @Test public void testGet32() {
+ int result = ZipUtil.get32(new byte[]{ 0x78, 0x56, 0x34, 0x12 }, 0);
+ assertThat(result).isEqualTo(0x12345678);
+ assertThat(result).isEqualTo(305419896);
+ }
+
+ @Test public void testGet32_Short() {
+ int result = ZipUtil.get32(new byte[]{ 0x34, (byte) 0xff, 0x0, 0x0 }, 0);
+ assertThat(result).isEqualTo(0xff34);
+ assertThat(result).isEqualTo(65332);
+ }
+
+ @Test public void testGet32_Signed() {
+ int result = ZipUtil.get32(new byte[]{ 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 0);
+ assertThat(result).isEqualTo(0xffffff34);
+ assertThat(result).isEqualTo(-204);
+ }
+
+ @Test public void testGetUnsignedShort() {
+ int result = ZipUtil.getUnsignedShort(new byte[]{ 0x34, 0x12 }, 0);
+ assertThat(result).isEqualTo(0x1234);
+ assertThat(result).isEqualTo(4660);
+ }
+
+ @Test public void testGetUnsignedShort_Big() {
+ int result = ZipUtil.getUnsignedShort(new byte[]{ 0x34, (byte) 0xff }, 0);
+ assertThat(result).isEqualTo(0xff34);
+ assertThat(result).isEqualTo(65332);
+ }
+
+ @Test public void testGetUnsignedInt() {
+ long result = ZipUtil.getUnsignedInt(new byte[]{ 0x34, 0x12, 0x0, 0x0 }, 0);
+ assertThat(result).isEqualTo(0x1234);
+ assertThat(result).isEqualTo(4660);
+ }
+
+ @Test public void testGetUnsignedInt_Big() {
+ long result = ZipUtil.getUnsignedInt(
+ new byte[]{ 0x34, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 0);
+ assertThat(result).isEqualTo(0xffffff34L);
+ assertThat(result).isEqualTo(4294967092L);
+ }
+
+ @Test public void testTimeConversion_DosToUnix() {
+ int dos = (20 << 25) | (2 << 21) | (14 << 16) | (3 << 11) | (7 << 5) | (15 >> 1);
+
+ Calendar time = new GregorianCalendar(2000, Calendar.FEBRUARY, 14, 3, 7, 14);
+ long expectedUnixTime = time.getTimeInMillis();
+ assertThat(ZipUtil.dosToUnixTime(dos)).isEqualTo(expectedUnixTime);
+ }
+
+ @Test public void testTimeConversion_UnixToDos() {
+ Calendar time = new GregorianCalendar(2000, Calendar.FEBRUARY, 14, 3, 7, 14);
+ long unix = time.getTimeInMillis();
+ int expectedDosTime = (20 << 25) | (2 << 21) | (14 << 16) | (3 << 11) | (7 << 5) | (15 >> 1);
+ assertThat(ZipUtil.unixToDosTime(unix)).isEqualTo(expectedDosTime);
+ }
+
+ @Test public void testTimeConversion_UnixToDos_LowBound() {
+ Calendar time = Calendar.getInstance();
+ time.setTimeInMillis(ZipUtil.DOS_EPOCH);
+ time.add(Calendar.SECOND, -1);
+ thrown.expect(IllegalArgumentException.class);
+ ZipUtil.unixToDosTime(time.getTimeInMillis());
+ }
+
+ @Test public void testTimeConversion_UnixToDos_HighBound_Rounding() {
+ Calendar time = Calendar.getInstance();
+ time.setTimeInMillis(ZipUtil.MAX_DOS_DATE);
+ ZipUtil.unixToDosTime(time.getTimeInMillis());
+ }
+
+ @Test public void testTimeConversion_UnixToDos_HighBound() {
+ Calendar time = Calendar.getInstance();
+ time.setTimeInMillis(ZipUtil.MAX_DOS_DATE);
+ time.add(Calendar.SECOND, 1);
+ thrown.expect(IllegalArgumentException.class);
+ ZipUtil.unixToDosTime(time.getTimeInMillis());
+ }
+
+ @Test public void testTimeConversion_UnixToUnix() {
+ Calendar from = new GregorianCalendar(2000, Calendar.FEBRUARY, 14, 3, 7, 15);
+ Calendar to = new GregorianCalendar(2000, Calendar.FEBRUARY, 14, 3, 7, 14);
+ assertThat(ZipUtil.dosToUnixTime(ZipUtil.unixToDosTime(from.getTimeInMillis())))
+ .isEqualTo(to.getTimeInMillis());
+ }
+
+ @Test public void testTimeConversion_DosToDos() {
+ int dos = (20 << 25) | (2 << 21) | (14 << 16) | (3 << 11) | (7 << 5) | (15 >> 1);
+ assertThat(ZipUtil.unixToDosTime(ZipUtil.dosToUnixTime(dos))).isEqualTo(dos);
+ }
+
+ @Test public void testTimeConversion_DosToDos_Zero() {
+ int dos = 0;
+ thrown.expect(IllegalArgumentException.class);
+ assertThat(ZipUtil.unixToDosTime(ZipUtil.dosToUnixTime(dos))).isEqualTo(0);
+ }
+}
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));
+ }
+ }
+}