1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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.android.tools.build.apkzlib.zip; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import com.google.common.base.Charsets; 26 import com.google.common.collect.ImmutableList; 27 import com.google.common.collect.Lists; 28 import com.google.common.collect.Maps; 29 import com.google.common.io.ByteStreams; 30 import com.google.common.io.Files; 31 import java.io.ByteArrayInputStream; 32 import java.io.File; 33 import java.io.InputStream; 34 import java.util.Arrays; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 import javax.annotation.Nonnull; 40 import javax.annotation.Nullable; 41 import org.junit.Assume; 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.Parameterized; 47 48 @RunWith(Parameterized.class) 49 public class ZipToolsTest { 50 51 @Parameterized.Parameter(0) 52 @Nullable 53 public String mZipFile; 54 55 @Parameterized.Parameter(1) 56 @Nullable 57 public List<String> mUnzipCommand; 58 59 @Parameterized.Parameter(2) 60 @Nullable 61 public String mUnzipLineRegex; 62 63 @Parameterized.Parameter(3) 64 public boolean mToolStoresDirectories; 65 66 @Parameterized.Parameter(4) 67 public String mName; 68 69 @Rule 70 @Nonnull 71 public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); 72 73 @Parameterized.Parameters(name = "{4} {index}") getConfigurations()74 public static Iterable<Object[]> getConfigurations() { 75 return Arrays.asList(new Object[][] { 76 { 77 "linux-zip.zip", 78 ImmutableList.of("/usr/bin/unzip", "-v"), 79 "^\\s*(?<size>\\d+)\\s+(?:Stored|Defl:N).*\\s(?<name>\\S+)\\S*$", 80 true, 81 "Linux Zip" 82 }, 83 { 84 "windows-7zip.zip", 85 ImmutableList.of("c:\\Program Files\\7-Zip\\7z.exe", "l"), 86 "^(?:\\S+\\s+){3}(?<size>\\d+)\\s+\\d+\\s+(?<name>\\S+)\\s*$", 87 true, 88 "Windows 7-Zip" 89 }, 90 { 91 "windows-cf.zip", 92 ImmutableList.of( 93 "Cannot use compressed folders from cmd line to list zip contents"), 94 "", 95 false, 96 "Windows Compressed Folders" 97 } 98 }); 99 } 100 cloneZipFile()101 private File cloneZipFile() throws Exception { 102 File zfile = mTemporaryFolder.newFile("file.zip"); 103 Files.write(ZipTestUtils.rsrcBytes(mZipFile), zfile); 104 return zfile; 105 } 106 assertFileInZip(@onnull ZFile zfile, @Nonnull String name)107 private static void assertFileInZip(@Nonnull ZFile zfile, @Nonnull String name) throws Exception { 108 StoredEntry root = zfile.get(name); 109 assertNotNull(root); 110 111 InputStream is = root.open(); 112 byte[] inZipData = ByteStreams.toByteArray(is); 113 is.close(); 114 115 byte[] inFileData = ZipTestUtils.rsrcBytes(name); 116 assertArrayEquals(inFileData, inZipData); 117 } 118 119 @Test zfileReadsZipFile()120 public void zfileReadsZipFile() throws Exception { 121 try (ZFile zf = new ZFile(cloneZipFile())) { 122 if (mToolStoresDirectories) { 123 assertEquals(6, zf.entries().size()); 124 } else { 125 assertEquals(4, zf.entries().size()); 126 } 127 128 assertFileInZip(zf, "root"); 129 assertFileInZip(zf, "images/lena.png"); 130 assertFileInZip(zf, "text-files/rfc2460.txt"); 131 assertFileInZip(zf, "text-files/wikipedia.html"); 132 } 133 } 134 135 @Test toolReadsZfFile()136 public void toolReadsZfFile() throws Exception { 137 testReadZFile(false); 138 } 139 140 @Test toolReadsAlignedZfFile()141 public void toolReadsAlignedZfFile() throws Exception { 142 testReadZFile(true); 143 } 144 testReadZFile(boolean align)145 private void testReadZFile(boolean align) throws Exception { 146 String unzipcmd = mUnzipCommand.get(0); 147 Assume.assumeTrue(new File(unzipcmd).canExecute()); 148 149 ZFileOptions options = new ZFileOptions(); 150 if (align) { 151 options.setAlignmentRule(AlignmentRules.constant(500)); 152 } 153 154 File zfile = new File (mTemporaryFolder.getRoot(), "zfile.zip"); 155 try (ZFile zf = new ZFile(zfile, options)) { 156 zf.add("root", new ByteArrayInputStream(ZipTestUtils.rsrcBytes("root"))); 157 zf.add("images/", new ByteArrayInputStream(new byte[0])); 158 zf.add( 159 "images/lena.png", 160 new ByteArrayInputStream(ZipTestUtils.rsrcBytes("images/lena.png"))); 161 zf.add("text-files/", new ByteArrayInputStream(new byte[0])); 162 zf.add( 163 "text-files/rfc2460.txt", 164 new ByteArrayInputStream(ZipTestUtils.rsrcBytes("text-files/rfc2460.txt"))); 165 zf.add( 166 "text-files/wikipedia.html", 167 new ByteArrayInputStream(ZipTestUtils.rsrcBytes("text-files/wikipedia.html"))); 168 } 169 170 List<String> command = Lists.newArrayList(mUnzipCommand); 171 command.add(zfile.getAbsolutePath()); 172 ProcessBuilder pb = new ProcessBuilder(command); 173 Process proc = pb.start(); 174 InputStream is = proc.getInputStream(); 175 byte output[] = ByteStreams.toByteArray(is); 176 String text = new String(output, Charsets.US_ASCII); 177 String lines[] = text.split("\n"); 178 Map<String, Integer> sizes = Maps.newHashMap(); 179 for (String l : lines) { 180 Matcher m = Pattern.compile(mUnzipLineRegex).matcher(l); 181 if (m.matches()) { 182 String sizeTxt = m.group("size"); 183 int size = Integer.parseInt(sizeTxt); 184 String name = m.group("name"); 185 sizes.put(name, size); 186 } 187 } 188 189 assertEquals(6, sizes.size()); 190 191 /* 192 * The "images" directory may show up as "images" or "images/". 193 */ 194 String imagesKey = "images/"; 195 if (!sizes.containsKey(imagesKey)) { 196 imagesKey = "images"; 197 } 198 199 assertTrue(sizes.containsKey(imagesKey)); 200 assertEquals(0, sizes.get(imagesKey).intValue()); 201 202 assertSize(new String[] { "images/", "images" }, 0, sizes); 203 assertSize(new String[] { "text-files/", "text-files"}, 0, sizes); 204 assertSize(new String[] { "root" }, ZipTestUtils.rsrcBytes("root").length, sizes); 205 assertSize(new String[] { "images/lena.png", "images\\lena.png" }, 206 ZipTestUtils.rsrcBytes("images/lena.png").length, sizes); 207 assertSize(new String[] { "text-files/rfc2460.txt", "text-files\\rfc2460.txt" }, 208 ZipTestUtils.rsrcBytes("text-files/rfc2460.txt").length, sizes); 209 assertSize(new String[] { "text-files/wikipedia.html", "text-files\\wikipedia.html" }, 210 ZipTestUtils.rsrcBytes("text-files/wikipedia.html").length, sizes); 211 } 212 assertSize(String[] names, long size, Map<String, Integer> sizes)213 private static void assertSize(String[] names, long size, Map<String, Integer> sizes) { 214 for (String n : names) { 215 if (sizes.containsKey(n)) { 216 assertEquals((long) sizes.get(n), size); 217 return; 218 } 219 } 220 221 fail(); 222 } 223 } 224