Home | History | Annotate | Download | only in io
      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 libcore.io;
     18 
     19 import junit.framework.TestCase;
     20 
     21 import java.io.File;
     22 import java.io.FileNotFoundException;
     23 import java.io.IOException;
     24 import java.net.JarURLConnection;
     25 import java.net.MalformedURLException;
     26 import java.net.URL;
     27 import java.net.URLConnection;
     28 import java.net.URLStreamHandler;
     29 import java.net.UnknownServiceException;
     30 import java.util.Arrays;
     31 
     32 import tests.support.resource.Support_Resources;
     33 
     34 public class ClassPathURLStreamHandlerTest extends TestCase {
     35 
     36     // A well formed jar file with 6 entries.
     37     private static final String JAR = "ClassPathURLStreamHandlerTest.jar";
     38     private static final String ENTRY_IN_ROOT = "root.txt";
     39     private static final String DIR_ENTRY_WITHOUT_SLASH = "foo";
     40     private static final String DIR_ENTRY_WITH_SLASH = DIR_ENTRY_WITHOUT_SLASH + "/";
     41     private static final String ENTRY_IN_SUBDIR = "foo/bar/baz.txt";
     42     private static final String ENTRY_STORED = "stored_file.txt";
     43     private static final String ENTRY_WITH_SPACES_ENCODED = "file%20with%20spaces.txt";
     44     private static final String ENTRY_WITH_SPACES_UNENCODED = "file with spaces.txt";
     45     private static final String ENTRY_THAT_NEEDS_ESCAPING = "file_with_percent20_%20.txt";
     46     private static final String ENTRY_THAT_NEEDS_ESCAPING_ENCODED = "file_with_percent20_%2520.txt";
     47     private static final String ENTRY_WITH_RELATIVE_PATH = "foo/../foo/bar/baz.txt";
     48     private static final String MISSING_ENTRY = "Wrong.resource";
     49 
     50     private File jarFile;
     51 
     52     @Override
     53     protected void setUp() throws Exception {
     54         File resources = Support_Resources.createTempFolder().getCanonicalFile();
     55         Support_Resources.copyFile(resources, null, JAR);
     56         jarFile = new File(resources, JAR);
     57     }
     58 
     59     public void testConstructor() throws Exception {
     60         try {
     61             ClassPathURLStreamHandler streamHandler = new ClassPathURLStreamHandler("Missing.file");
     62             fail("Should throw IOException");
     63         } catch (IOException expected) {
     64         }
     65 
     66         String fileName = jarFile.getPath();
     67         ClassPathURLStreamHandler streamHandler = new ClassPathURLStreamHandler(fileName);
     68         streamHandler.close();
     69     }
     70 
     71     public void testGetEntryOrNull() throws Exception {
     72         String fileName = jarFile.getPath();
     73         ClassPathURLStreamHandler streamHandler = new ClassPathURLStreamHandler(fileName);
     74 
     75         checkGetEntryUrlOrNull(streamHandler, ENTRY_IN_ROOT, ENTRY_IN_ROOT);
     76         checkGetEntryUrlOrNull(streamHandler, ENTRY_IN_SUBDIR, ENTRY_IN_SUBDIR);
     77         checkGetEntryUrlOrNull(streamHandler, ENTRY_WITH_SPACES_UNENCODED,
     78                 ENTRY_WITH_SPACES_ENCODED);
     79         checkGetEntryUrlOrNull(streamHandler, ENTRY_THAT_NEEDS_ESCAPING,
     80                 ENTRY_THAT_NEEDS_ESCAPING_ENCODED);
     81 
     82         // getEntryOrNull() performs a lookup with and without trailing slash to handle directories.
     83         // http://b/22527772
     84         checkGetEntryUrlOrNull(streamHandler, DIR_ENTRY_WITHOUT_SLASH,
     85                 DIR_ENTRY_WITHOUT_SLASH);
     86         checkGetEntryUrlOrNull(streamHandler, DIR_ENTRY_WITH_SLASH, DIR_ENTRY_WITH_SLASH);
     87 
     88         assertNull(streamHandler.getEntryUrlOrNull(MISSING_ENTRY));
     89         assertNull(streamHandler.getEntryUrlOrNull("/" + ENTRY_IN_ROOT));
     90         assertNull(streamHandler.getEntryUrlOrNull("/" + ENTRY_IN_SUBDIR));
     91         assertNull(streamHandler.getEntryUrlOrNull(ENTRY_WITH_SPACES_ENCODED));
     92         assertNull(streamHandler.getEntryUrlOrNull(ENTRY_WITH_RELATIVE_PATH));
     93         assertNull(streamHandler.getEntryUrlOrNull("/" + DIR_ENTRY_WITHOUT_SLASH));
     94         assertNull(streamHandler.getEntryUrlOrNull("/" + DIR_ENTRY_WITH_SLASH));
     95         streamHandler.close();
     96     }
     97 
     98     /**
     99      * Check that the call to {@link ClassPathURLStreamHandler#getEntryUrlOrNull(String)} works as
    100      * expected.
    101      */
    102     private void checkGetEntryUrlOrNull(ClassPathURLStreamHandler streamHandler,
    103             String entryName, String expectedJarRelativeURI) throws IOException {
    104 
    105         String fileName = jarFile.getPath();
    106         URL urlOrNull = streamHandler.getEntryUrlOrNull(entryName);
    107         assertNotNull("URL was unexpectedly null for " + entryName, urlOrNull);
    108         assertEquals("jar:file:" + fileName + "!/" + expectedJarRelativeURI,
    109                 urlOrNull.toExternalForm());
    110 
    111         // Make sure that the resource could be opened and the correct contents returned, i.e. the
    112         // same as those read from the jar file directly.
    113         assertOpenConnectionOk(jarFile, expectedJarRelativeURI, streamHandler);
    114     }
    115 
    116     public void testIsEntryStored() throws IOException {
    117         String fileName = jarFile.getPath();
    118         ClassPathURLStreamHandler streamHandler = new ClassPathURLStreamHandler(fileName);
    119 
    120         assertFalse(streamHandler.isEntryStored("this/file/does/not/exist.txt"));
    121         // This one is compressed
    122         assertFalse(streamHandler.isEntryStored(ENTRY_IN_SUBDIR));
    123         assertTrue(streamHandler.isEntryStored(ENTRY_STORED));
    124 
    125         assertTrue(streamHandler.isEntryStored(DIR_ENTRY_WITHOUT_SLASH));
    126 
    127         // Directory entries are just stored, empty entries with "/" on the end of the name, so
    128         // "true".
    129         assertTrue(streamHandler.isEntryStored(DIR_ENTRY_WITH_SLASH));
    130     }
    131 
    132     public void testOpenConnection() throws Exception {
    133         String fileName = jarFile.getPath();
    134         ClassPathURLStreamHandler streamHandler = new ClassPathURLStreamHandler(fileName);
    135 
    136         assertOpenConnectionOk(jarFile, ENTRY_IN_ROOT, streamHandler);
    137         assertOpenConnectionOk(jarFile, ENTRY_IN_SUBDIR, streamHandler);
    138         assertOpenConnectionOk(jarFile, ENTRY_WITH_SPACES_ENCODED, streamHandler);
    139         assertOpenConnectionOk(jarFile, ENTRY_WITH_SPACES_UNENCODED, streamHandler);
    140         assertOpenConnectionOk(jarFile, DIR_ENTRY_WITH_SLASH, streamHandler);
    141         assertOpenConnectionOk(jarFile, DIR_ENTRY_WITHOUT_SLASH, streamHandler);
    142 
    143         assertOpenConnectionConnectFails(jarFile, ENTRY_WITH_RELATIVE_PATH, streamHandler);
    144         assertOpenConnectionConnectFails(jarFile, MISSING_ENTRY, streamHandler);
    145         assertOpenConnectionConnectFails(jarFile, ENTRY_THAT_NEEDS_ESCAPING, streamHandler);
    146 
    147         streamHandler.close();
    148     }
    149 
    150     private void assertOpenConnectionConnectFails(
    151             File jarFile, String entryName, URLStreamHandler streamHandler) throws IOException {
    152 
    153         URL standardUrl = createJarUrl(jarFile, entryName, null /* use default stream handler */);
    154         try {
    155             standardUrl.openConnection().connect();
    156             fail();
    157         } catch (FileNotFoundException expected) {
    158         }
    159 
    160         URL actualUrl = createJarUrl(jarFile, entryName, streamHandler);
    161         try {
    162             actualUrl.openConnection().connect();
    163             fail();
    164         } catch (FileNotFoundException expected) {
    165         }
    166     }
    167 
    168     private static void assertOpenConnectionOk(File jarFile, String entryName,
    169             ClassPathURLStreamHandler streamHandler) throws IOException {
    170         URL standardUrl = createJarUrl(jarFile, entryName, null /* use default stream handler */);
    171         URLConnection standardUrlConnection = standardUrl.openConnection();
    172         assertNotNull(standardUrlConnection);
    173 
    174         URL actualUrl = createJarUrl(jarFile, entryName, streamHandler);
    175         URLConnection actualUrlConnection = actualUrl.openConnection();
    176         assertNotNull(actualUrlConnection);
    177         assertBehaviorSame(standardUrlConnection, actualUrlConnection);
    178     }
    179 
    180     private static void assertBehaviorSame(URLConnection standardURLConnection,
    181             URLConnection actualUrlConnection) throws IOException {
    182 
    183         JarURLConnection standardJarUrlConnection = (JarURLConnection) standardURLConnection;
    184         JarURLConnection actualJarUrlConnection = (JarURLConnection) actualUrlConnection;
    185 
    186         byte[] actualBytes = Streams.readFully(actualJarUrlConnection.getInputStream());
    187         byte[] standardBytes = Streams.readFully(standardJarUrlConnection.getInputStream());
    188         assertEquals(Arrays.toString(standardBytes), Arrays.toString(actualBytes));
    189 
    190         try {
    191             actualJarUrlConnection.getOutputStream();
    192             fail();
    193         } catch (UnknownServiceException expected) {
    194         }
    195 
    196         assertEquals(
    197                 standardJarUrlConnection.getJarFile().getName(),
    198                 actualJarUrlConnection.getJarFile().getName());
    199 
    200         assertEquals(
    201                 standardJarUrlConnection.getJarEntry().getName(),
    202                 actualJarUrlConnection.getJarEntry().getName());
    203 
    204         assertEquals(
    205                 standardJarUrlConnection.getJarFileURL(),
    206                 actualJarUrlConnection.getJarFileURL());
    207 
    208         assertEquals(
    209                 standardJarUrlConnection.getContentType(),
    210                 actualJarUrlConnection.getContentType());
    211 
    212         assertEquals(
    213                 standardJarUrlConnection.getContentLength(),
    214                 actualJarUrlConnection.getContentLength());
    215     }
    216 
    217     private static URL createJarUrl(File jarFile, String entryName, URLStreamHandler streamHandler)
    218             throws MalformedURLException {
    219         return new URL("jar", null, -1, jarFile.toURI() + "!/" + entryName, streamHandler);
    220     }
    221 
    222 }
    223