Home | History | Annotate | Download | only in zip
      1 /*
      2  * Copyright 2017 Google Inc. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.turbine.zip;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 import static java.nio.charset.StandardCharsets.UTF_8;
     21 import static org.junit.Assert.fail;
     22 
     23 import com.google.common.collect.ImmutableMap;
     24 import com.google.common.hash.Hashing;
     25 import com.google.common.io.ByteStreams;
     26 import java.io.IOException;
     27 import java.net.URI;
     28 import java.nio.file.FileSystem;
     29 import java.nio.file.FileSystems;
     30 import java.nio.file.Files;
     31 import java.nio.file.Path;
     32 import java.nio.file.StandardOpenOption;
     33 import java.nio.file.attribute.FileTime;
     34 import java.util.Enumeration;
     35 import java.util.LinkedHashMap;
     36 import java.util.Map;
     37 import java.util.jar.JarEntry;
     38 import java.util.jar.JarFile;
     39 import java.util.jar.JarOutputStream;
     40 import java.util.zip.ZipException;
     41 import java.util.zip.ZipOutputStream;
     42 import org.junit.Rule;
     43 import org.junit.Test;
     44 import org.junit.rules.TemporaryFolder;
     45 import org.junit.runner.RunWith;
     46 import org.junit.runners.JUnit4;
     47 
     48 /** {@link Zip}Test */
     49 @RunWith(JUnit4.class)
     50 public class ZipTest {
     51 
     52   @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
     53 
     54   @Test
     55   public void testEntries() throws IOException {
     56     testEntries(1000);
     57   }
     58 
     59   @Test
     60   public void zip64_testEntries() throws IOException {
     61     testEntries(70000);
     62   }
     63 
     64   @Test
     65   public void compression() throws IOException {
     66     Path path = temporaryFolder.newFile("test.jar").toPath();
     67     try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(path))) {
     68       for (int i = 0; i < 2; i++) {
     69         String name = "entry" + i;
     70         byte[] bytes = name.getBytes(UTF_8);
     71         jos.putNextEntry(new JarEntry(name));
     72         jos.write(bytes);
     73       }
     74     }
     75     assertThat(actual(path)).isEqualTo(expected(path));
     76   }
     77 
     78   private void testEntries(int entries) throws IOException {
     79     Path path = temporaryFolder.newFile("test.jar").toPath();
     80     try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(path))) {
     81       for (int i = 0; i < entries; i++) {
     82         String name = "entry" + i;
     83         byte[] bytes = name.getBytes(UTF_8);
     84         createEntry(jos, name, bytes);
     85       }
     86     }
     87     assertThat(actual(path)).isEqualTo(expected(path));
     88   }
     89 
     90   private static void createEntry(ZipOutputStream jos, String name, byte[] bytes)
     91       throws IOException {
     92     JarEntry je = new JarEntry(name);
     93     je.setMethod(JarEntry.STORED);
     94     je.setSize(bytes.length);
     95     je.setCrc(Hashing.crc32().hashBytes(bytes).padToLong());
     96     jos.putNextEntry(je);
     97     jos.write(bytes);
     98   }
     99 
    100   private static Map<String, Long> actual(Path path) throws IOException {
    101     Map<String, Long> result = new LinkedHashMap<>();
    102     for (Zip.Entry e : new Zip.ZipIterable(path)) {
    103       result.put(e.name(), Hashing.goodFastHash(128).hashBytes(e.data()).padToLong());
    104     }
    105     return result;
    106   }
    107 
    108   private static Map<String, Long> expected(Path path) throws IOException {
    109     Map<String, Long> result = new LinkedHashMap<>();
    110     try (JarFile jf = new JarFile(path.toFile())) {
    111       Enumeration<JarEntry> entries = jf.entries();
    112       while (entries.hasMoreElements()) {
    113         JarEntry je = entries.nextElement();
    114         result.put(
    115             je.getName(),
    116             Hashing.goodFastHash(128)
    117                 .hashBytes(ByteStreams.toByteArray(jf.getInputStream(je)))
    118                 .padToLong());
    119       }
    120     }
    121     return result;
    122   }
    123 
    124   @Test
    125   public void attributes() throws Exception {
    126     Path path = temporaryFolder.newFile("test.jar").toPath();
    127     Files.delete(path);
    128     try (FileSystem fs =
    129         FileSystems.newFileSystem(
    130             URI.create("jar:file:" + path.toAbsolutePath()), ImmutableMap.of("create", "true"))) {
    131       for (int i = 0; i < 3; i++) {
    132         String name = "entry" + i;
    133         byte[] bytes = name.getBytes(UTF_8);
    134         Path entry = fs.getPath(name);
    135         Files.write(entry, bytes);
    136         Files.setLastModifiedTime(entry, FileTime.fromMillis(0));
    137       }
    138     }
    139     assertThat(actual(path)).isEqualTo(expected(path));
    140   }
    141 
    142   @Test
    143   public void zipFileCommentsAreSupported() throws Exception {
    144     Path path = temporaryFolder.newFile("test.jar").toPath();
    145     Files.delete(path);
    146     try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(path))) {
    147       createEntry(zos, "hello", "world".getBytes(UTF_8));
    148       zos.setComment("this is a comment");
    149     }
    150     assertThat(actual(path)).isEqualTo(expected(path));
    151   }
    152 
    153   @Test
    154   public void malformedComment() throws Exception {
    155     Path path = temporaryFolder.newFile("test.jar").toPath();
    156     Files.delete(path);
    157 
    158     try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(path))) {
    159       createEntry(zos, "hello", "world".getBytes(UTF_8));
    160       zos.setComment("this is a comment");
    161     }
    162     Files.write(path, "trailing garbage".getBytes(UTF_8), StandardOpenOption.APPEND);
    163 
    164     try {
    165       actual(path);
    166       fail();
    167     } catch (ZipException e) {
    168       assertThat(e).hasMessage("zip file comment length was 33, expected 17");
    169     }
    170   }
    171 }
    172