| /* |
| * Copyright 2017 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.turbine.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.common.collect.ImmutableMap; |
| import com.google.common.hash.Hashing; |
| import com.google.common.io.ByteStreams; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.nio.file.FileSystem; |
| import java.nio.file.FileSystems; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.StandardOpenOption; |
| import java.nio.file.attribute.FileTime; |
| import java.util.Enumeration; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| import java.util.jar.JarOutputStream; |
| import java.util.zip.ZipException; |
| import java.util.zip.ZipOutputStream; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TemporaryFolder; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** {@link Zip}Test */ |
| @RunWith(JUnit4.class) |
| public class ZipTest { |
| |
| @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); |
| |
| @Test |
| public void testEntries() throws IOException { |
| testEntries(1000); |
| } |
| |
| @Test |
| public void zip64_testEntries() throws IOException { |
| testEntries(70000); |
| } |
| |
| @Test |
| public void compression() throws IOException { |
| Path path = temporaryFolder.newFile("test.jar").toPath(); |
| try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(path))) { |
| for (int i = 0; i < 2; i++) { |
| String name = "entry" + i; |
| byte[] bytes = name.getBytes(UTF_8); |
| jos.putNextEntry(new JarEntry(name)); |
| jos.write(bytes); |
| } |
| } |
| assertThat(actual(path)).isEqualTo(expected(path)); |
| } |
| |
| private void testEntries(int entries) throws IOException { |
| Path path = temporaryFolder.newFile("test.jar").toPath(); |
| try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(path))) { |
| for (int i = 0; i < entries; i++) { |
| String name = "entry" + i; |
| byte[] bytes = name.getBytes(UTF_8); |
| createEntry(jos, name, bytes); |
| } |
| } |
| assertThat(actual(path)).isEqualTo(expected(path)); |
| } |
| |
| private static void createEntry(ZipOutputStream jos, String name, byte[] bytes) |
| throws IOException { |
| JarEntry je = new JarEntry(name); |
| je.setMethod(JarEntry.STORED); |
| je.setSize(bytes.length); |
| je.setCrc(Hashing.crc32().hashBytes(bytes).padToLong()); |
| jos.putNextEntry(je); |
| jos.write(bytes); |
| } |
| |
| private static Map<String, Long> actual(Path path) throws IOException { |
| Map<String, Long> result = new LinkedHashMap<>(); |
| for (Zip.Entry e : new Zip.ZipIterable(path)) { |
| result.put(e.name(), Hashing.goodFastHash(128).hashBytes(e.data()).padToLong()); |
| } |
| return result; |
| } |
| |
| private static Map<String, Long> expected(Path path) throws IOException { |
| Map<String, Long> result = new LinkedHashMap<>(); |
| try (JarFile jf = new JarFile(path.toFile())) { |
| Enumeration<JarEntry> entries = jf.entries(); |
| while (entries.hasMoreElements()) { |
| JarEntry je = entries.nextElement(); |
| result.put( |
| je.getName(), |
| Hashing.goodFastHash(128) |
| .hashBytes(ByteStreams.toByteArray(jf.getInputStream(je))) |
| .padToLong()); |
| } |
| } |
| return result; |
| } |
| |
| @Test |
| public void attributes() throws Exception { |
| Path path = temporaryFolder.newFile("test.jar").toPath(); |
| Files.delete(path); |
| try (FileSystem fs = |
| FileSystems.newFileSystem( |
| URI.create("jar:file:" + path.toAbsolutePath()), ImmutableMap.of("create", "true"))) { |
| for (int i = 0; i < 3; i++) { |
| String name = "entry" + i; |
| byte[] bytes = name.getBytes(UTF_8); |
| Path entry = fs.getPath(name); |
| Files.write(entry, bytes); |
| Files.setLastModifiedTime(entry, FileTime.fromMillis(0)); |
| } |
| } |
| assertThat(actual(path)).isEqualTo(expected(path)); |
| } |
| |
| @Test |
| public void zipFileCommentsAreSupported() throws Exception { |
| Path path = temporaryFolder.newFile("test.jar").toPath(); |
| Files.delete(path); |
| try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(path))) { |
| createEntry(zos, "hello", "world".getBytes(UTF_8)); |
| zos.setComment("this is a comment"); |
| } |
| assertThat(actual(path)).isEqualTo(expected(path)); |
| } |
| |
| @Test |
| public void malformedComment() throws Exception { |
| Path path = temporaryFolder.newFile("test.jar").toPath(); |
| Files.delete(path); |
| |
| try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(path))) { |
| createEntry(zos, "hello", "world".getBytes(UTF_8)); |
| zos.setComment("this is a comment"); |
| } |
| Files.write(path, "trailing garbage".getBytes(UTF_8), StandardOpenOption.APPEND); |
| |
| try { |
| actual(path); |
| fail(); |
| } catch (ZipException e) { |
| assertThat(e).hasMessage("zip file comment length was 33, expected 17"); |
| } |
| } |
| } |