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