test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
changeset 58864 fba8635290df
child 59057 c8e15590c7cc
equal deleted inserted replaced
58863:c16ac7a2eba4 58864:fba8635290df
       
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 import org.testng.annotations.AfterClass;
       
    26 import org.testng.annotations.BeforeClass;
       
    27 import org.testng.annotations.Test;
       
    28 
       
    29 import java.io.IOException;
       
    30 import java.io.InputStream;
       
    31 import java.nio.charset.StandardCharsets;
       
    32 import java.nio.file.FileSystem;
       
    33 import java.nio.file.FileSystems;
       
    34 import java.nio.file.Files;
       
    35 import java.nio.file.Path;
       
    36 import java.util.Arrays;
       
    37 import java.util.HashMap;
       
    38 import java.util.Map;
       
    39 import java.util.zip.ZipEntry;
       
    40 import java.util.zip.ZipFile;
       
    41 
       
    42 import static org.testng.Assert.*;
       
    43 
       
    44 /**
       
    45  * @test
       
    46  * @bug 8231451
       
    47  * @summary Basic tests for ZipFileInputStream::skip
       
    48  * @modules jdk.zipfs
       
    49  * @run testng/othervm ZipFileInputStreamSkipTest
       
    50  */
       
    51 public class ZipFileInputStreamSkipTest {
       
    52 
       
    53     // Stored and Deflated Zip File paths used by the tests
       
    54     private final Path STORED_ZIPFILE = Path.of("skipStoredEntries.zip");
       
    55     private final Path DEFLATED_ZIPFILE = Path.of("skipDeflatedEntries.zip");
       
    56 
       
    57     // Saved Entries added to the relevant Zip file
       
    58     private final HashMap<String, Entry> STORED_ZIP_ENTRIES = new HashMap<>();
       
    59     private final HashMap<String, Entry> DEFLATED_ZIP_ENTRIES = new HashMap<>();
       
    60 
       
    61     /**
       
    62      * Create the Zip Files used by the tests
       
    63      *
       
    64      * @throws IOException If an error occurs creating the Zip Files
       
    65      */
       
    66     @BeforeClass
       
    67     private void createZip() throws IOException {
       
    68         Entry e0 = Entry.of("Entry-0", ZipEntry.STORED, "Tennis Pro");
       
    69         Entry e1 = Entry.of("Entry-1", ZipEntry.STORED,
       
    70                 "United States Tennis Association");
       
    71         Entry e2 = Entry.of("Entry-2", ZipEntry.DEFLATED, "Cardio Tennis");
       
    72         Entry e3 = Entry.of("Entry-3", ZipEntry.DEFLATED, "USTA League Championships");
       
    73 
       
    74         // Add entries
       
    75         STORED_ZIP_ENTRIES.put(e0.name, e0);
       
    76         STORED_ZIP_ENTRIES.put(e1.name, e1);
       
    77         DEFLATED_ZIP_ENTRIES.put(e2.name, e2);
       
    78         DEFLATED_ZIP_ENTRIES.put(e3.name, e3);
       
    79 
       
    80         Files.deleteIfExists(STORED_ZIPFILE);
       
    81         Files.deleteIfExists(DEFLATED_ZIPFILE);
       
    82 
       
    83         createZipFile(STORED_ZIPFILE,
       
    84                 Map.of("create", "true", "noCompression", "true"),
       
    85                 e0, e1);
       
    86 
       
    87         createZipFile(DEFLATED_ZIPFILE, Map.of("create", "true"), e2, e3);
       
    88     }
       
    89 
       
    90     /**
       
    91      * Delete Zip Files created for the test
       
    92      *
       
    93      * @throws IOException If an error occurs during cleanup
       
    94      */
       
    95     @AfterClass
       
    96     private void cleanUp() throws IOException {
       
    97         Files.deleteIfExists(STORED_ZIPFILE);
       
    98         Files.deleteIfExists(DEFLATED_ZIPFILE);
       
    99     }
       
   100 
       
   101     /**
       
   102      * Validate that you can skip forward within a STORED entry
       
   103      * and then read the expected data for the entry
       
   104      *
       
   105      * @throws Exception If an error occurs during the test
       
   106      */
       
   107     @Test
       
   108     private void testStoredSkip() throws Exception {
       
   109 
       
   110         try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
       
   111             var entries = zf.entries();
       
   112             while (entries.hasMoreElements()) {
       
   113                 var entry = entries.nextElement();
       
   114                 var entrySize = entry.getSize();
       
   115                 long midpoint = entrySize / 2;
       
   116                 Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
       
   117                 assertNotNull(expected);
       
   118                 try (InputStream in = zf.getInputStream(entry)) {
       
   119 
       
   120                     // Check that if we specify 0, that we return the correct
       
   121                     // skip value value
       
   122                     assertEquals(in.skip(0), 0);
       
   123 
       
   124                     // Try to skip past EOF and should return remaining bytes
       
   125                     assertEquals(in.skip(entrySize + 100), entrySize);
       
   126 
       
   127                     // Return to BOF and then specify a value which would
       
   128                     // overflow the projected skip value and return the
       
   129                     // number of bytes moved to reach EOF
       
   130                     assertEquals(in.skip(-entrySize), -entrySize);
       
   131                     assertEquals(in.skip(Long.MAX_VALUE), entrySize);
       
   132 
       
   133                     // From midpoint, try to skip past EOF and then skip back
       
   134                     // to BOF
       
   135                     assertEquals(in.skip(-entrySize), -entrySize);
       
   136                     assertEquals(in.skip(midpoint), midpoint);
       
   137                     assertEquals(in.skip(1000), entrySize - midpoint);
       
   138                     assertEquals(in.skip(-entrySize), -entrySize);
       
   139 
       
   140                     // Read remaining bytes and validate against expected bytes
       
   141                     byte[] bytes = in.readAllBytes();
       
   142                     assertEquals(bytes, expected.bytes);
       
   143                     assertEquals(bytes.length, expected.bytes.length);
       
   144                 }
       
   145             }
       
   146         }
       
   147     }
       
   148 
       
   149     /**
       
   150      * Validate that you can skip backwards within a STORED entry
       
   151      * and then read the expected data for the entry
       
   152      *
       
   153      * @throws Exception If an error occurs during the test
       
   154      */
       
   155     @Test
       
   156     private void testStoredNegativeSkip() throws Exception {
       
   157 
       
   158         try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
       
   159             var entries = zf.entries();
       
   160             while (entries.hasMoreElements()) {
       
   161                 var entry = entries.nextElement();
       
   162                 var entrySize = entry.getSize();
       
   163                 var midpoint = entrySize / 2;
       
   164                 Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
       
   165                 assertNotNull(expected);
       
   166                 try (InputStream in = zf.getInputStream(entry)) {
       
   167 
       
   168                     // Check that if you try to move past BOF
       
   169                     // that we return the correct value
       
   170                     assertEquals(in.skip(-1), 0);
       
   171                     assertEquals(in.skip(-100), 0);
       
   172                     assertEquals(in.skip(Long.MIN_VALUE), 0);
       
   173 
       
   174                     // Go to midpoint in file; then specify a value before
       
   175                     // BOF which should result in the number of
       
   176                     // bytes to BOF returned
       
   177                     assertEquals(in.skip(midpoint), midpoint);
       
   178                     assertEquals(in.skip(-(midpoint + 10)), -midpoint);
       
   179 
       
   180                     // From midpoint, move back a couple of bytes
       
   181                     assertEquals(in.skip(midpoint), midpoint);
       
   182                     assertEquals(in.skip(-2), -2);
       
   183 
       
   184                     // Read the remaining bytes and compare to the expected bytes
       
   185                     byte[] bytes = in.readAllBytes();
       
   186                     assertEquals(bytes, Arrays.copyOfRange(expected.bytes,
       
   187                             (int)midpoint - 2, (int) entrySize));
       
   188                     assertEquals(bytes.length, entrySize - midpoint + 2);
       
   189                 }
       
   190             }
       
   191         }
       
   192     }
       
   193 
       
   194     /**
       
   195      * Validate that you can skip forward within a DEFLATED entry
       
   196      * and then read the expected data for the entry
       
   197      *
       
   198      * @throws Exception If an error occurs during the test
       
   199      */
       
   200     @Test
       
   201     private void testDeflatedSkip() throws Exception {
       
   202         try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
       
   203             var toSkip = 5; // Bytes to Skip
       
   204             var entries = zf.entries();
       
   205             while (entries.hasMoreElements()) {
       
   206                 var entry = entries.nextElement();
       
   207                 Entry expected = DEFLATED_ZIP_ENTRIES.get(entry.getName());
       
   208                 assertNotNull(expected);
       
   209                 try (InputStream in = zf.getInputStream(entry)) {
       
   210                     assertEquals(in.skip(toSkip), toSkip);
       
   211                     byte[] bytes = in.readAllBytes();
       
   212                     var ebytes = Arrays.copyOfRange(expected.bytes,
       
   213                             toSkip, expected.bytes.length);
       
   214                     assertEquals(bytes, ebytes);
       
   215                     assertEquals(bytes.length, expected.bytes.length - toSkip);
       
   216                 }
       
   217             }
       
   218         }
       
   219     }
       
   220 
       
   221     /**
       
   222      * Validate that an IllegalArgumentException is thrown if you specify
       
   223      * a negative skip value for a DEFLATED entry.
       
   224      *
       
   225      * @throws Exception If an unexpected error occurs during the test
       
   226      */
       
   227     @Test
       
   228     private void testDeflatedIOException() throws Exception {
       
   229         try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
       
   230             var entries = zf.entries();
       
   231             while (entries.hasMoreElements()) {
       
   232                 var entry = entries.nextElement();
       
   233                 assertNotNull(entry);
       
   234                 try (InputStream in = zf.getInputStream(entry)) {
       
   235                     // Cannot specify a negative value
       
   236                     assertThrows(IllegalArgumentException.class, () -> in.skip((-1)));
       
   237                 }
       
   238             }
       
   239         }
       
   240     }
       
   241 
       
   242     /**
       
   243      * Create a Zip File System using the specified properties and a Zip file
       
   244      * with the specified number of entries
       
   245      *
       
   246      * @param zipFile Path to the Zip File to create
       
   247      * @param env     Properties used for creating the Zip Filesystem
       
   248      * @param entries The entries to add to the Zip File
       
   249      * @throws IOException If an error occurs while creating the Zip file
       
   250      */
       
   251     private void createZipFile(Path zipFile, Map<String, String> env,
       
   252                                Entry... entries) throws IOException {
       
   253         try (FileSystem zipfs =
       
   254                      FileSystems.newFileSystem(zipFile, env)) {
       
   255             for (Entry e : entries) {
       
   256                 Files.writeString(zipfs.getPath(e.name), new String(e.bytes));
       
   257             }
       
   258         }
       
   259     }
       
   260 
       
   261     /**
       
   262      * Represents an entry in a Zip file. An entry encapsulates a name, a
       
   263      * compression method, and its contents/data.
       
   264      */
       
   265     static class Entry {
       
   266         private final String name;
       
   267         private final int method;
       
   268         private final byte[] bytes;
       
   269 
       
   270         Entry(String name, int method, String contents) {
       
   271             this.name = name;
       
   272             this.method = method;
       
   273             this.bytes = contents.getBytes(StandardCharsets.UTF_8);
       
   274         }
       
   275 
       
   276         static Entry of(String name, int method, String contents) {
       
   277             return new Entry(name, method, contents);
       
   278         }
       
   279 
       
   280         /**
       
   281          * Returns a new Entry with the same name and compression method as this
       
   282          * Entry but with the given content.
       
   283          */
       
   284         Entry content(String contents) {
       
   285             return new Entry(name, method, contents);
       
   286         }
       
   287     }
       
   288 
       
   289 }