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