blob: cf48b210941498ee2b29d440cdaf2a46c6ab6ff7 [file] [log] [blame]
package org.robolectric.res.android;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit test for {@link ZipFileRO}. */
@RunWith(JUnit4.class)
public final class ZipFileROTest {
/** Verify that ZIP entries can be located when there are gaps between them. */
//
// The test data (zip_with_gap.zip) was crafted by creating a regular ZIP file with two
// uncompressed entries, adding 32 spaces between them, and adjusting offsets accordingly
// (in particular, the contents of the Central Directory and EOCD).
//
// 00000000: 504b 0304 0a00 0000 0000 0000 2100 a865 PK..........!..e
// 00000010: 327e 0400 0000 0400 0000 0200 0000 6630 2~............f0
// 00000020: 666f 6f0a 2020 2020 2020 2020 2020 2020 foo.
// 00000030: 2020 2020 2020 2020 2020 2020 2020 2020
// 00000040: 2020 2020 504b 0304 0a00 0000 0000 0000 PK..........
// 00000050: 2100 e9b3 a204 0400 0000 0400 0000 0200 !...............
// 00000060: 0000 6631 6261 720a 504b 0102 1e03 0a00 ..f1bar.PK......
// 00000070: 0000 0000 0000 2100 a865 327e 0400 0000 ......!..e2~....
// 00000080: 0400 0000 0200 0000 0000 0000 0000 0000 ................
// 00000090: a081 0000 0000 6630 504b 0102 1e03 0a00 ......f0PK......
// 000000a0: 0000 0000 0000 2100 e9b3 a204 0400 0000 ......!.........
// 000000b0: 0400 0000 0200 0000 0000 0000 0000 0000 ................
// 000000c0: a081 4400 0000 6631 504b 0506 0000 0000 ..D...f1PK......
// 000000d0: 0200 0200 6000 0000 6800 0000 0000 ....`...h.....
@Test
public void createEntryFileMap_yieldsCorrectOffset() throws Exception {
// Write the test data (provided as a JAR resource) to a regular file.
// JAR resources are preferred as input since they don't depend on the working directory, but we
// want a real file for testing.
File blob = File.createTempFile("prefix", "zip");
try (InputStream input = getClass().getResourceAsStream("/zip_with_gap.zip");
FileOutputStream output = new FileOutputStream(blob)) {
ByteStreams.copy(input, output);
}
ZipFileRO zipFile = ZipFileRO.open(blob.toString());
ZipFileRO.ZipEntryRO entry = zipFile.findEntryByName("f1");
FileMap fileMap = zipFile.createEntryFileMap(entry);
// The contents of file "f1" (i.e. "bar") appears at offset 0x64.
assertThat(fileMap.getDataOffset()).isEqualTo(0x64);
}
@Test
public void open_emptyZip() throws Exception {
// ensure ZipFileRO cam handle an empty zip file with no central directory
File blob = File.createTempFile("prefix", "zip");
try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(blob))) {}
ZipFileRO zipFile = ZipFileRO.open(blob.toString());
assertThat(zipFile).isNotNull();
}
@Test
public void testCreateJar() throws Exception {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(byteArrayOutputStream);
// Write 2^16 + 1 entries, forcing zip64 EOCD to be written.
for (int i = 0; i < 65537; i++) {
out.putNextEntry(new ZipEntry(Integer.toString(i)));
out.closeEntry();
}
out.close();
byte[] zipBytes = byteArrayOutputStream.toByteArray();
// Write 0xff for the following fields in the EOCD, which some zip libraries do.
// Entries in this disk (2 bytes)
// Total Entries (2 byte)
// Size of Central Dir (4 bytes)
// Offset to Central Dir (4 bytes)
// Total: 12 bytes
for (int i = 0; i < 12; i++) {
zipBytes[zipBytes.length - 3 - i] = (byte) 0xff;
}
File tmpFile = File.createTempFile("zip64eocd", "zip");
Files.write(zipBytes, tmpFile);
ZipFileRO zro = ZipFileRO.open(tmpFile.getAbsolutePath());
assertThat(zro).isNotNull();
assertThat(zro.findEntryByName("0")).isNotNull();
assertThat(zro.findEntryByName("65536")).isNotNull();
assertThat(zro.findEntryByName("65537")).isNull();
}
}