14ca254fbe
Reviewed-by: lancea
290 lines
11 KiB
Java
290 lines
11 KiB
Java
/*
|
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
import org.testng.annotations.AfterClass;
|
|
import org.testng.annotations.BeforeClass;
|
|
import org.testng.annotations.Test;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.FileSystem;
|
|
import java.nio.file.FileSystems;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipFile;
|
|
|
|
import static org.testng.Assert.*;
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8231451
|
|
* @summary Basic tests for ZipFileInputStream::skip
|
|
* @modules jdk.zipfs
|
|
* @run testng/othervm ZipFileInputStreamSkipTest
|
|
*/
|
|
public class ZipFileInputStreamSkipTest {
|
|
|
|
// Stored and Deflated Zip File paths used by the tests
|
|
private final Path STORED_ZIPFILE = Path.of("skipStoredEntries.zip");
|
|
private final Path DEFLATED_ZIPFILE = Path.of("skipDeflatedEntries.zip");
|
|
|
|
// Saved Entries added to the relevant Zip file
|
|
private final HashMap<String, Entry> STORED_ZIP_ENTRIES = new HashMap<>();
|
|
private final HashMap<String, Entry> DEFLATED_ZIP_ENTRIES = new HashMap<>();
|
|
|
|
/**
|
|
* Create the Zip Files used by the tests
|
|
*
|
|
* @throws IOException If an error occurs creating the Zip Files
|
|
*/
|
|
@BeforeClass
|
|
private void createZip() throws IOException {
|
|
Entry e0 = Entry.of("Entry-0", ZipEntry.STORED, "Tennis Pro");
|
|
Entry e1 = Entry.of("Entry-1", ZipEntry.STORED,
|
|
"United States Tennis Association");
|
|
Entry e2 = Entry.of("Entry-2", ZipEntry.DEFLATED, "Cardio Tennis");
|
|
Entry e3 = Entry.of("Entry-3", ZipEntry.DEFLATED, "USTA League Championships");
|
|
|
|
// Add entries
|
|
STORED_ZIP_ENTRIES.put(e0.name, e0);
|
|
STORED_ZIP_ENTRIES.put(e1.name, e1);
|
|
DEFLATED_ZIP_ENTRIES.put(e2.name, e2);
|
|
DEFLATED_ZIP_ENTRIES.put(e3.name, e3);
|
|
|
|
Files.deleteIfExists(STORED_ZIPFILE);
|
|
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
|
|
|
createZipFile(STORED_ZIPFILE,
|
|
Map.of("create", "true", "noCompression", "true"),
|
|
e0, e1);
|
|
|
|
createZipFile(DEFLATED_ZIPFILE, Map.of("create", "true"), e2, e3);
|
|
}
|
|
|
|
/**
|
|
* Delete Zip Files created for the test
|
|
*
|
|
* @throws IOException If an error occurs during cleanup
|
|
*/
|
|
@AfterClass
|
|
private void cleanUp() throws IOException {
|
|
Files.deleteIfExists(STORED_ZIPFILE);
|
|
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
|
}
|
|
|
|
/**
|
|
* Validate that you can skip forward within a STORED entry
|
|
* and then read the expected data for the entry
|
|
*
|
|
* @throws Exception If an error occurs during the test
|
|
*/
|
|
@Test
|
|
public void testStoredSkip() throws Exception {
|
|
|
|
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
|
var entries = zf.entries();
|
|
while (entries.hasMoreElements()) {
|
|
var entry = entries.nextElement();
|
|
var entrySize = entry.getSize();
|
|
long midpoint = entrySize / 2;
|
|
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
|
assertNotNull(expected);
|
|
try (InputStream in = zf.getInputStream(entry)) {
|
|
|
|
// Check that if we specify 0, that we return the correct
|
|
// skip value value
|
|
assertEquals(in.skip(0), 0);
|
|
|
|
// Try to skip past EOF and should return remaining bytes
|
|
assertEquals(in.skip(entrySize + 100), entrySize);
|
|
|
|
// Return to BOF and then specify a value which would
|
|
// overflow the projected skip value and return the
|
|
// number of bytes moved to reach EOF
|
|
assertEquals(in.skip(-entrySize), -entrySize);
|
|
assertEquals(in.skip(Long.MAX_VALUE), entrySize);
|
|
|
|
// From midpoint, try to skip past EOF and then skip back
|
|
// to BOF
|
|
assertEquals(in.skip(-entrySize), -entrySize);
|
|
assertEquals(in.skip(midpoint), midpoint);
|
|
assertEquals(in.skip(1000), entrySize - midpoint);
|
|
assertEquals(in.skip(-entrySize), -entrySize);
|
|
|
|
// Read remaining bytes and validate against expected bytes
|
|
byte[] bytes = in.readAllBytes();
|
|
assertEquals(bytes, expected.bytes);
|
|
assertEquals(bytes.length, expected.bytes.length);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that you can skip backwards within a STORED entry
|
|
* and then read the expected data for the entry
|
|
*
|
|
* @throws Exception If an error occurs during the test
|
|
*/
|
|
@Test
|
|
public void testStoredNegativeSkip() throws Exception {
|
|
|
|
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
|
var entries = zf.entries();
|
|
while (entries.hasMoreElements()) {
|
|
var entry = entries.nextElement();
|
|
var entrySize = entry.getSize();
|
|
var midpoint = entrySize / 2;
|
|
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
|
assertNotNull(expected);
|
|
try (InputStream in = zf.getInputStream(entry)) {
|
|
|
|
// Check that if you try to move past BOF
|
|
// that we return the correct value
|
|
assertEquals(in.skip(-1), 0);
|
|
assertEquals(in.skip(-100), 0);
|
|
assertEquals(in.skip(Long.MIN_VALUE), 0);
|
|
|
|
// Go to midpoint in file; then specify a value before
|
|
// BOF which should result in the number of
|
|
// bytes to BOF returned
|
|
assertEquals(in.skip(midpoint), midpoint);
|
|
assertEquals(in.skip(-(midpoint + 10)), -midpoint);
|
|
|
|
// From midpoint, move back a couple of bytes
|
|
assertEquals(in.skip(midpoint), midpoint);
|
|
assertEquals(in.skip(-2), -2);
|
|
|
|
// Read the remaining bytes and compare to the expected bytes
|
|
byte[] bytes = in.readAllBytes();
|
|
assertEquals(bytes, Arrays.copyOfRange(expected.bytes,
|
|
(int)midpoint - 2, (int) entrySize));
|
|
assertEquals(bytes.length, entrySize - midpoint + 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that you can skip forward within a DEFLATED entry
|
|
* and then read the expected data for the entry
|
|
*
|
|
* @throws Exception If an error occurs during the test
|
|
*/
|
|
@Test
|
|
public void testDeflatedSkip() throws Exception {
|
|
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
|
var toSkip = 5; // Bytes to Skip
|
|
var entries = zf.entries();
|
|
while (entries.hasMoreElements()) {
|
|
var entry = entries.nextElement();
|
|
Entry expected = DEFLATED_ZIP_ENTRIES.get(entry.getName());
|
|
assertNotNull(expected);
|
|
try (InputStream in = zf.getInputStream(entry)) {
|
|
assertEquals(in.skip(toSkip), toSkip);
|
|
byte[] bytes = in.readAllBytes();
|
|
var ebytes = Arrays.copyOfRange(expected.bytes,
|
|
toSkip, expected.bytes.length);
|
|
assertEquals(bytes, ebytes);
|
|
assertEquals(bytes.length, expected.bytes.length - toSkip);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that an IllegalArgumentException is thrown if you specify
|
|
* a negative skip value for a DEFLATED entry.
|
|
*
|
|
* @throws Exception If an unexpected error occurs during the test
|
|
*/
|
|
@Test
|
|
public void testDeflatedIOException() throws Exception {
|
|
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
|
var entries = zf.entries();
|
|
while (entries.hasMoreElements()) {
|
|
var entry = entries.nextElement();
|
|
assertNotNull(entry);
|
|
try (InputStream in = zf.getInputStream(entry)) {
|
|
// Cannot specify a negative value
|
|
assertThrows(IllegalArgumentException.class, () -> in.skip((-1)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a Zip File System using the specified properties and a Zip file
|
|
* with the specified number of entries
|
|
*
|
|
* @param zipFile Path to the Zip File to create
|
|
* @param env Properties used for creating the Zip Filesystem
|
|
* @param entries The entries to add to the Zip File
|
|
* @throws IOException If an error occurs while creating the Zip file
|
|
*/
|
|
private void createZipFile(Path zipFile, Map<String, String> env,
|
|
Entry... entries) throws IOException {
|
|
try (FileSystem zipfs =
|
|
FileSystems.newFileSystem(zipFile, env)) {
|
|
for (Entry e : entries) {
|
|
Files.writeString(zipfs.getPath(e.name), new String(e.bytes));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Represents an entry in a Zip file. An entry encapsulates a name, a
|
|
* compression method, and its contents/data.
|
|
*/
|
|
static class Entry {
|
|
private final String name;
|
|
private final int method;
|
|
private final byte[] bytes;
|
|
|
|
Entry(String name, int method, String contents) {
|
|
this.name = name;
|
|
this.method = method;
|
|
this.bytes = contents.getBytes(StandardCharsets.UTF_8);
|
|
}
|
|
|
|
static Entry of(String name, int method, String contents) {
|
|
return new Entry(name, method, contents);
|
|
}
|
|
|
|
/**
|
|
* Returns a new Entry with the same name and compression method as this
|
|
* Entry but with the given content.
|
|
*/
|
|
Entry content(String contents) {
|
|
return new Entry(name, method, contents);
|
|
}
|
|
}
|
|
|
|
}
|