1 /* 2 * Copyright (C) 2012 The Guava Authors 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 package com.google.common.reflect; 17 18 import static com.google.common.base.Charsets.US_ASCII; 19 import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH; 20 import static com.google.common.base.StandardSystemProperty.OS_NAME; 21 import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR; 22 import static com.google.common.truth.Truth.assertThat; 23 24 import com.google.common.base.Joiner; 25 import com.google.common.collect.ImmutableList; 26 import com.google.common.collect.ImmutableSet; 27 import com.google.common.io.Closer; 28 import com.google.common.io.Files; 29 import com.google.common.io.Resources; 30 import com.google.common.reflect.ClassPath.ClassInfo; 31 import com.google.common.reflect.ClassPath.ResourceInfo; 32 import com.google.common.testing.EqualsTester; 33 import com.google.common.testing.NullPointerTester; 34 import java.io.ByteArrayInputStream; 35 import java.io.File; 36 import java.io.FileOutputStream; 37 import java.io.FilePermission; 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.net.MalformedURLException; 41 import java.net.URISyntaxException; 42 import java.net.URL; 43 import java.net.URLClassLoader; 44 import java.security.Permission; 45 import java.security.PermissionCollection; 46 import java.util.jar.Attributes; 47 import java.util.jar.JarOutputStream; 48 import java.util.jar.Manifest; 49 import java.util.logging.Logger; 50 import java.util.zip.ZipEntry; 51 import junit.framework.TestCase; 52 import org.junit.Test; 53 54 /** Functional tests of {@link ClassPath}. */ 55 public class ClassPathTest extends TestCase { 56 private static final Logger log = Logger.getLogger(ClassPathTest.class.getName()); 57 private static final File FILE = new File("."); 58 testEquals()59 public void testEquals() { 60 new EqualsTester() 61 .addEqualityGroup(classInfo(ClassPathTest.class), classInfo(ClassPathTest.class)) 62 .addEqualityGroup(classInfo(Test.class), classInfo(Test.class, getClass().getClassLoader())) 63 .addEqualityGroup( 64 new ResourceInfo(FILE, "a/b/c.txt", getClass().getClassLoader()), 65 new ResourceInfo(FILE, "a/b/c.txt", getClass().getClassLoader())) 66 .addEqualityGroup(new ResourceInfo(FILE, "x.txt", getClass().getClassLoader())) 67 .testEquals(); 68 } 69 70 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_emptyURLClassLoader_noParent()71 public void testClassPathEntries_emptyURLClassLoader_noParent() { 72 assertThat(ClassPath.getClassPathEntries(new URLClassLoader(new URL[0], null)).keySet()) 73 .isEmpty(); 74 } 75 76 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_URLClassLoader_noParent()77 public void testClassPathEntries_URLClassLoader_noParent() throws Exception { 78 URL url1 = new URL("file:/a"); 79 URL url2 = new URL("file:/b"); 80 URLClassLoader classloader = new URLClassLoader(new URL[] {url1, url2}, null); 81 assertThat(ClassPath.getClassPathEntries(classloader)) 82 .containsExactly(new File("/a"), classloader, new File("/b"), classloader); 83 } 84 85 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_URLClassLoader_withParent()86 public void testClassPathEntries_URLClassLoader_withParent() throws Exception { 87 URL url1 = new URL("file:/a"); 88 URL url2 = new URL("file:/b"); 89 URLClassLoader parent = new URLClassLoader(new URL[] {url1}, null); 90 URLClassLoader child = new URLClassLoader(new URL[] {url2}, parent) {}; 91 assertThat(ClassPath.getClassPathEntries(child)) 92 .containsExactly(new File("/a"), parent, new File("/b"), child) 93 .inOrder(); 94 } 95 96 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_duplicateUri_parentWins()97 public void testClassPathEntries_duplicateUri_parentWins() throws Exception { 98 URL url = new URL("file:/a"); 99 URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); 100 URLClassLoader child = new URLClassLoader(new URL[] {url}, parent) {}; 101 assertThat(ClassPath.getClassPathEntries(child)).containsExactly(new File("/a"), parent); 102 } 103 104 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_notURLClassLoader_noParent()105 public void testClassPathEntries_notURLClassLoader_noParent() { 106 assertThat(ClassPath.getClassPathEntries(new ClassLoader(null) {})).isEmpty(); 107 } 108 109 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_notURLClassLoader_withParent()110 public void testClassPathEntries_notURLClassLoader_withParent() throws Exception { 111 URL url = new URL("file:/a"); 112 URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); 113 assertThat(ClassPath.getClassPathEntries(new ClassLoader(parent) {})) 114 .containsExactly(new File("/a"), parent); 115 } 116 117 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_notURLClassLoader_withParentAndGrandParent()118 public void testClassPathEntries_notURLClassLoader_withParentAndGrandParent() throws Exception { 119 URL url1 = new URL("file:/a"); 120 URL url2 = new URL("file:/b"); 121 URLClassLoader grandParent = new URLClassLoader(new URL[] {url1}, null); 122 URLClassLoader parent = new URLClassLoader(new URL[] {url2}, grandParent); 123 assertThat(ClassPath.getClassPathEntries(new ClassLoader(parent) {})) 124 .containsExactly(new File("/a"), grandParent, new File("/b"), parent); 125 } 126 127 @AndroidIncompatible // Android forbids null parent ClassLoader testClassPathEntries_notURLClassLoader_withGrandParent()128 public void testClassPathEntries_notURLClassLoader_withGrandParent() throws Exception { 129 URL url = new URL("file:/a"); 130 URLClassLoader grandParent = new URLClassLoader(new URL[] {url}, null); 131 ClassLoader parent = new ClassLoader(grandParent) {}; 132 assertThat(ClassPath.getClassPathEntries(new ClassLoader(parent) {})) 133 .containsExactly(new File("/a"), grandParent); 134 } 135 136 @AndroidIncompatible // Android forbids null parent ClassLoader 137 // https://github.com/google/guava/issues/2152 testClassPathEntries_URLClassLoader_pathWithSpace()138 public void testClassPathEntries_URLClassLoader_pathWithSpace() throws Exception { 139 URL url = new URL("file:///c:/Documents and Settings/"); 140 URLClassLoader classloader = new URLClassLoader(new URL[] {url}, null); 141 assertThat(ClassPath.getClassPathEntries(classloader)) 142 .containsExactly(new File("/c:/Documents and Settings/"), classloader); 143 } 144 145 @AndroidIncompatible // Android forbids null parent ClassLoader 146 // https://github.com/google/guava/issues/2152 testClassPathEntries_URLClassLoader_pathWithEscapedSpace()147 public void testClassPathEntries_URLClassLoader_pathWithEscapedSpace() throws Exception { 148 URL url = new URL("file:///c:/Documents%20and%20Settings/"); 149 URLClassLoader classloader = new URLClassLoader(new URL[] {url}, null); 150 assertThat(ClassPath.getClassPathEntries(classloader)) 151 .containsExactly(new File("/c:/Documents and Settings/"), classloader); 152 } 153 154 // https://github.com/google/guava/issues/2152 testToFile()155 public void testToFile() throws Exception { 156 assertThat(ClassPath.toFile(new URL("file:///c:/Documents%20and%20Settings/"))) 157 .isEqualTo(new File("/c:/Documents and Settings/")); 158 assertThat(ClassPath.toFile(new URL("file:///c:/Documents ~ Settings, or not/11-12 12:05"))) 159 .isEqualTo(new File("/c:/Documents ~ Settings, or not/11-12 12:05")); 160 } 161 162 // https://github.com/google/guava/issues/2152 163 @AndroidIncompatible // works in newer Android versions but fails at the version we test with testToFile_AndroidIncompatible()164 public void testToFile_AndroidIncompatible() throws Exception { 165 assertThat(ClassPath.toFile(new URL("file:///c:\\Documents ~ Settings, or not\\11-12 12:05"))) 166 .isEqualTo(new File("/c:\\Documents ~ Settings, or not\\11-12 12:05")); 167 assertThat(ClassPath.toFile(new URL("file:///C:\\Program Files\\Apache Software Foundation"))) 168 .isEqualTo(new File("/C:\\Program Files\\Apache Software Foundation/")); 169 assertThat(ClassPath.toFile(new URL("file:///C:\\\u20320 \u22909"))) // Chinese Ni Hao 170 .isEqualTo(new File("/C:\\\u20320 \u22909")); 171 } 172 173 174 @AndroidIncompatible // Android forbids null parent ClassLoader 175 // https://github.com/google/guava/issues/2152 testJarFileWithSpaces()176 public void testJarFileWithSpaces() throws Exception { 177 URL url = makeJarUrlWithName("To test unescaped spaces in jar file name.jar"); 178 URLClassLoader classloader = new URLClassLoader(new URL[] {url}, null); 179 assertThat(ClassPath.from(classloader).getTopLevelClasses()).isNotEmpty(); 180 } 181 182 @AndroidIncompatible // ClassPath is documented as not supporting Android 183 testScan_classPathCycle()184 public void testScan_classPathCycle() throws IOException { 185 File jarFile = File.createTempFile("with_circular_class_path", ".jar"); 186 try { 187 writeSelfReferencingJarFile(jarFile, "test.txt"); 188 assertThat( 189 new ClassPath.LocationInfo(jarFile, ClassPathTest.class.getClassLoader()) 190 .scanResources()) 191 .hasSize(1); 192 } finally { 193 jarFile.delete(); 194 } 195 } 196 197 testScanFromFile_fileNotExists()198 public void testScanFromFile_fileNotExists() throws IOException { 199 ClassLoader classLoader = ClassPathTest.class.getClassLoader(); 200 assertThat( 201 new ClassPath.LocationInfo(new File("no/such/file/anywhere"), classLoader) 202 .scanResources()) 203 .isEmpty(); 204 } 205 206 @AndroidIncompatible // ClassPath is documented as not supporting Android 207 testScanFromFile_notJarFile()208 public void testScanFromFile_notJarFile() throws IOException { 209 ClassLoader classLoader = ClassPathTest.class.getClassLoader(); 210 File notJar = File.createTempFile("not_a_jar", "txt"); 211 try { 212 assertThat(new ClassPath.LocationInfo(notJar, classLoader).scanResources()).isEmpty(); 213 } finally { 214 notJar.delete(); 215 } 216 } 217 testGetClassPathEntry()218 public void testGetClassPathEntry() throws MalformedURLException, URISyntaxException { 219 if (isWindows()) { 220 return; // TODO: b/136041958 - We need to account for drive letters in the path. 221 } 222 assertEquals( 223 new File("/usr/test/dep.jar").toURI(), 224 ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "file:/usr/test/dep.jar") 225 .toURI()); 226 assertEquals( 227 new File("/home/build/a.jar").toURI(), 228 ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "a.jar").toURI()); 229 assertEquals( 230 new File("/home/build/x/y/z").toURI(), 231 ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z").toURI()); 232 assertEquals( 233 new File("/home/build/x/y/z.jar").toURI(), 234 ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z.jar").toURI()); 235 assertEquals( 236 "/home/build/x y.jar", 237 ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "x y.jar").getFile()); 238 } 239 testGetClassPathFromManifest_nullManifest()240 public void testGetClassPathFromManifest_nullManifest() { 241 assertThat(ClassPath.getClassPathFromManifest(new File("some.jar"), null)).isEmpty(); 242 } 243 testGetClassPathFromManifest_noClassPath()244 public void testGetClassPathFromManifest_noClassPath() throws IOException { 245 File jarFile = new File("base.jar"); 246 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest(""))).isEmpty(); 247 } 248 testGetClassPathFromManifest_emptyClassPath()249 public void testGetClassPathFromManifest_emptyClassPath() throws IOException { 250 File jarFile = new File("base.jar"); 251 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifestClasspath(""))).isEmpty(); 252 } 253 testGetClassPathFromManifest_badClassPath()254 public void testGetClassPathFromManifest_badClassPath() throws IOException { 255 File jarFile = new File("base.jar"); 256 Manifest manifest = manifestClasspath("nosuchscheme:an_invalid^path"); 257 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)).isEmpty(); 258 } 259 testGetClassPathFromManifest_pathWithStrangeCharacter()260 public void testGetClassPathFromManifest_pathWithStrangeCharacter() throws IOException { 261 File jarFile = new File("base/some.jar"); 262 Manifest manifest = manifestClasspath("file:the^file.jar"); 263 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 264 .containsExactly(fullpath("base/the^file.jar")); 265 } 266 testGetClassPathFromManifest_relativeDirectory()267 public void testGetClassPathFromManifest_relativeDirectory() throws IOException { 268 File jarFile = new File("base/some.jar"); 269 // with/relative/directory is the Class-Path value in the mf file. 270 Manifest manifest = manifestClasspath("with/relative/dir"); 271 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 272 .containsExactly(fullpath("base/with/relative/dir")); 273 } 274 testGetClassPathFromManifest_relativeJar()275 public void testGetClassPathFromManifest_relativeJar() throws IOException { 276 File jarFile = new File("base/some.jar"); 277 // with/relative/directory is the Class-Path value in the mf file. 278 Manifest manifest = manifestClasspath("with/relative.jar"); 279 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 280 .containsExactly(fullpath("base/with/relative.jar")); 281 } 282 testGetClassPathFromManifest_jarInCurrentDirectory()283 public void testGetClassPathFromManifest_jarInCurrentDirectory() throws IOException { 284 File jarFile = new File("base/some.jar"); 285 // with/relative/directory is the Class-Path value in the mf file. 286 Manifest manifest = manifestClasspath("current.jar"); 287 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 288 .containsExactly(fullpath("base/current.jar")); 289 } 290 testGetClassPathFromManifest_absoluteDirectory()291 public void testGetClassPathFromManifest_absoluteDirectory() throws IOException { 292 if (isWindows()) { 293 return; // TODO: b/136041958 - We need to account for drive letters in the path. 294 } 295 File jarFile = new File("base/some.jar"); 296 Manifest manifest = manifestClasspath("file:/with/absolute/dir"); 297 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 298 .containsExactly(fullpath("/with/absolute/dir")); 299 } 300 testGetClassPathFromManifest_absoluteJar()301 public void testGetClassPathFromManifest_absoluteJar() throws IOException { 302 if (isWindows()) { 303 return; // TODO: b/136041958 - We need to account for drive letters in the path. 304 } 305 File jarFile = new File("base/some.jar"); 306 Manifest manifest = manifestClasspath("file:/with/absolute.jar"); 307 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 308 .containsExactly(fullpath("/with/absolute.jar")); 309 } 310 testGetClassPathFromManifest_multiplePaths()311 public void testGetClassPathFromManifest_multiplePaths() throws IOException { 312 if (isWindows()) { 313 return; // TODO: b/136041958 - We need to account for drive letters in the path. 314 } 315 File jarFile = new File("base/some.jar"); 316 Manifest manifest = manifestClasspath("file:/with/absolute.jar relative.jar relative/dir"); 317 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 318 .containsExactly( 319 fullpath("/with/absolute.jar"), 320 fullpath("base/relative.jar"), 321 fullpath("base/relative/dir")) 322 .inOrder(); 323 } 324 testGetClassPathFromManifest_leadingBlanks()325 public void testGetClassPathFromManifest_leadingBlanks() throws IOException { 326 File jarFile = new File("base/some.jar"); 327 Manifest manifest = manifestClasspath(" relative.jar"); 328 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 329 .containsExactly(fullpath("base/relative.jar")); 330 } 331 testGetClassPathFromManifest_trailingBlanks()332 public void testGetClassPathFromManifest_trailingBlanks() throws IOException { 333 File jarFile = new File("base/some.jar"); 334 Manifest manifest = manifestClasspath("relative.jar "); 335 assertThat(ClassPath.getClassPathFromManifest(jarFile, manifest)) 336 .containsExactly(fullpath("base/relative.jar")); 337 } 338 testGetClassName()339 public void testGetClassName() { 340 assertEquals("abc.d.Abc", ClassPath.getClassName("abc/d/Abc.class")); 341 } 342 testResourceInfo_of()343 public void testResourceInfo_of() { 344 assertEquals(ClassInfo.class, resourceInfo(ClassPathTest.class).getClass()); 345 assertEquals(ClassInfo.class, resourceInfo(ClassPath.class).getClass()); 346 assertEquals(ClassInfo.class, resourceInfo(Nested.class).getClass()); 347 } 348 testGetSimpleName()349 public void testGetSimpleName() { 350 ClassLoader classLoader = getClass().getClassLoader(); 351 assertEquals("Foo", new ClassInfo(FILE, "Foo.class", classLoader).getSimpleName()); 352 assertEquals("Foo", new ClassInfo(FILE, "a/b/Foo.class", classLoader).getSimpleName()); 353 assertEquals("Foo", new ClassInfo(FILE, "a/b/Bar$Foo.class", classLoader).getSimpleName()); 354 assertEquals("", new ClassInfo(FILE, "a/b/Bar$1.class", classLoader).getSimpleName()); 355 assertEquals("Foo", new ClassInfo(FILE, "a/b/Bar$Foo.class", classLoader).getSimpleName()); 356 assertEquals("", new ClassInfo(FILE, "a/b/Bar$1.class", classLoader).getSimpleName()); 357 assertEquals("Local", new ClassInfo(FILE, "a/b/Bar$1Local.class", classLoader).getSimpleName()); 358 } 359 testGetPackageName()360 public void testGetPackageName() { 361 assertEquals( 362 "", new ClassInfo(FILE, "Foo.class", getClass().getClassLoader()).getPackageName()); 363 assertEquals( 364 "a.b", new ClassInfo(FILE, "a/b/Foo.class", getClass().getClassLoader()).getPackageName()); 365 } 366 367 // Test that ResourceInfo.urls() returns identical content to ClassLoader.getResources() 368 369 370 @AndroidIncompatible testGetClassPathUrls()371 public void testGetClassPathUrls() throws Exception { 372 if (isWindows()) { 373 return; // TODO: b/136041958 - We need to account for drive letters in the path. 374 } 375 String oldPathSeparator = PATH_SEPARATOR.value(); 376 String oldClassPath = JAVA_CLASS_PATH.value(); 377 System.setProperty(PATH_SEPARATOR.key(), ":"); 378 System.setProperty( 379 JAVA_CLASS_PATH.key(), 380 Joiner.on(":") 381 .join( 382 "relative/path/to/some.jar", 383 "/absolute/path/to/some.jar", 384 "relative/path/to/class/root", 385 "/absolute/path/to/class/root")); 386 try { 387 ImmutableList<URL> urls = ClassPath.parseJavaClassPath(); 388 389 assertThat(urls.get(0).getProtocol()).isEqualTo("file"); 390 assertThat(urls.get(0).getAuthority()).isNull(); 391 assertThat(urls.get(0).getPath()).endsWith("/relative/path/to/some.jar"); 392 393 assertThat(urls.get(1)).isEqualTo(new URL("file:///absolute/path/to/some.jar")); 394 395 assertThat(urls.get(2).getProtocol()).isEqualTo("file"); 396 assertThat(urls.get(2).getAuthority()).isNull(); 397 assertThat(urls.get(2).getPath()).endsWith("/relative/path/to/class/root"); 398 399 assertThat(urls.get(3)).isEqualTo(new URL("file:///absolute/path/to/class/root")); 400 401 assertThat(urls).hasSize(4); 402 } finally { 403 System.setProperty(PATH_SEPARATOR.key(), oldPathSeparator); 404 System.setProperty(JAVA_CLASS_PATH.key(), oldClassPath); 405 } 406 } 407 contentEquals(URL left, URL right)408 private static boolean contentEquals(URL left, URL right) throws IOException { 409 return Resources.asByteSource(left).contentEquals(Resources.asByteSource(right)); 410 } 411 412 private static class Nested {} 413 414 testNulls()415 public void testNulls() throws IOException { 416 new NullPointerTester().testAllPublicStaticMethods(ClassPath.class); 417 new NullPointerTester() 418 .testAllPublicInstanceMethods(ClassPath.from(getClass().getClassLoader())); 419 } 420 421 @AndroidIncompatible // ClassPath is documented as not supporting Android 422 testLocationsFrom_idempotentScan()423 public void testLocationsFrom_idempotentScan() throws IOException { 424 ImmutableSet<ClassPath.LocationInfo> locations = 425 ClassPath.locationsFrom(getClass().getClassLoader()); 426 assertThat(locations).isNotEmpty(); 427 for (ClassPath.LocationInfo location : locations) { 428 ImmutableSet<ResourceInfo> resources = location.scanResources(); 429 assertThat(location.scanResources()).containsExactlyElementsIn(resources); 430 } 431 } 432 testLocationsFrom_idempotentLocations()433 public void testLocationsFrom_idempotentLocations() { 434 ImmutableSet<ClassPath.LocationInfo> locations = 435 ClassPath.locationsFrom(getClass().getClassLoader()); 436 assertThat(ClassPath.locationsFrom(getClass().getClassLoader())) 437 .containsExactlyElementsIn(locations); 438 } 439 testLocationEquals()440 public void testLocationEquals() { 441 ClassLoader child = getClass().getClassLoader(); 442 ClassLoader parent = child.getParent(); 443 new EqualsTester() 444 .addEqualityGroup( 445 new ClassPath.LocationInfo(new File("foo.jar"), child), 446 new ClassPath.LocationInfo(new File("foo.jar"), child)) 447 .addEqualityGroup(new ClassPath.LocationInfo(new File("foo.jar"), parent)) 448 .addEqualityGroup(new ClassPath.LocationInfo(new File("foo"), child)) 449 .testEquals(); 450 } 451 452 @AndroidIncompatible // ClassPath is documented as not supporting Android 453 testScanAllResources()454 public void testScanAllResources() throws IOException { 455 assertThat(scanResourceNames(ClassLoader.getSystemClassLoader())) 456 .contains("com/google/common/reflect/ClassPathTest.class"); 457 } 458 459 testExistsThrowsSecurityException()460 public void testExistsThrowsSecurityException() throws IOException, URISyntaxException { 461 SecurityManager oldSecurityManager = System.getSecurityManager(); 462 try { 463 doTestExistsThrowsSecurityException(); 464 } finally { 465 System.setSecurityManager(oldSecurityManager); 466 } 467 } 468 doTestExistsThrowsSecurityException()469 private void doTestExistsThrowsSecurityException() throws IOException, URISyntaxException { 470 File file = null; 471 // In Java 9, Logger may read the TZ database. Only disallow reading the class path URLs. 472 final PermissionCollection readClassPathFiles = 473 new FilePermission("", "read").newPermissionCollection(); 474 for (URL url : ClassPath.parseJavaClassPath()) { 475 if (url.getProtocol().equalsIgnoreCase("file")) { 476 file = new File(url.toURI()); 477 readClassPathFiles.add(new FilePermission(file.getAbsolutePath(), "read")); 478 } 479 } 480 assertThat(file).isNotNull(); 481 SecurityManager disallowFilesSecurityManager = 482 new SecurityManager() { 483 @Override 484 public void checkPermission(Permission p) { 485 if (readClassPathFiles.implies(p)) { 486 throw new SecurityException("Disallowed: " + p); 487 } 488 } 489 }; 490 System.setSecurityManager(disallowFilesSecurityManager); 491 try { 492 file.exists(); 493 fail("Did not get expected SecurityException"); 494 } catch (SecurityException expected) { 495 } 496 ClassPath classPath = ClassPath.from(getClass().getClassLoader()); 497 // ClassPath may contain resources from the boot class loader; just not from the class path. 498 for (ResourceInfo resource : classPath.getResources()) { 499 assertThat(resource.getResourceName()).doesNotContain("com/google/common/reflect/"); 500 } 501 } 502 findClass( Iterable<ClassPath.ClassInfo> classes, Class<?> cls)503 private static ClassPath.ClassInfo findClass( 504 Iterable<ClassPath.ClassInfo> classes, Class<?> cls) { 505 for (ClassPath.ClassInfo classInfo : classes) { 506 if (classInfo.getName().equals(cls.getName())) { 507 return classInfo; 508 } 509 } 510 throw new AssertionError("failed to find " + cls); 511 } 512 resourceInfo(Class<?> cls)513 private static ResourceInfo resourceInfo(Class<?> cls) { 514 String resource = cls.getName().replace('.', '/') + ".class"; 515 ClassLoader loader = cls.getClassLoader(); 516 return ResourceInfo.of(FILE, resource, loader); 517 } 518 classInfo(Class<?> cls)519 private static ClassInfo classInfo(Class<?> cls) { 520 return classInfo(cls, cls.getClassLoader()); 521 } 522 classInfo(Class<?> cls, ClassLoader classLoader)523 private static ClassInfo classInfo(Class<?> cls, ClassLoader classLoader) { 524 String resource = cls.getName().replace('.', '/') + ".class"; 525 return new ClassInfo(FILE, resource, classLoader); 526 } 527 manifestClasspath(String classpath)528 private static Manifest manifestClasspath(String classpath) throws IOException { 529 return manifest("Class-Path: " + classpath + "\n"); 530 } 531 writeSelfReferencingJarFile(File jarFile, String... entries)532 private static void writeSelfReferencingJarFile(File jarFile, String... entries) 533 throws IOException { 534 Manifest manifest = new Manifest(); 535 // Without version, the manifest is silently ignored. Ugh! 536 manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); 537 manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, jarFile.getName()); 538 539 Closer closer = Closer.create(); 540 try { 541 FileOutputStream fileOut = closer.register(new FileOutputStream(jarFile)); 542 JarOutputStream jarOut = closer.register(new JarOutputStream(fileOut)); 543 for (String entry : entries) { 544 jarOut.putNextEntry(new ZipEntry(entry)); 545 Resources.copy(ClassPathTest.class.getResource(entry), jarOut); 546 jarOut.closeEntry(); 547 } 548 } catch (Throwable e) { 549 throw closer.rethrow(e); 550 } finally { 551 closer.close(); 552 } 553 } 554 manifest(String content)555 private static Manifest manifest(String content) throws IOException { 556 InputStream in = new ByteArrayInputStream(content.getBytes(US_ASCII)); 557 Manifest manifest = new Manifest(); 558 manifest.read(in); 559 return manifest; 560 } 561 fullpath(String path)562 private static File fullpath(String path) { 563 return new File(new File(path).toURI()); 564 } 565 makeJarUrlWithName(String name)566 private static URL makeJarUrlWithName(String name) throws IOException { 567 /* 568 * TODO: cpovirk - Use java.nio.file.Files.createTempDirectory instead of 569 * c.g.c.io.Files.createTempDir? 570 */ 571 File fullPath = new File(Files.createTempDir(), name); 572 File jarFile = pickAnyJarFile(); 573 Files.copy(jarFile, fullPath); 574 return fullPath.toURI().toURL(); 575 } 576 pickAnyJarFile()577 private static File pickAnyJarFile() throws IOException { 578 for (ClassPath.LocationInfo location : 579 ClassPath.locationsFrom(ClassPathTest.class.getClassLoader())) { 580 if (!location.file().isDirectory() && location.file().exists()) { 581 return location.file(); 582 } 583 } 584 throw new AssertionError("Failed to find a jar file"); 585 } 586 scanResourceNames(ClassLoader loader)587 private static ImmutableSet<String> scanResourceNames(ClassLoader loader) throws IOException { 588 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 589 for (ClassPath.LocationInfo location : ClassPath.locationsFrom(loader)) { 590 for (ResourceInfo resource : location.scanResources()) { 591 builder.add(resource.getResourceName()); 592 } 593 } 594 return builder.build(); 595 } 596 isWindows()597 private static boolean isWindows() { 598 return OS_NAME.value().startsWith("Windows"); 599 } 600 } 601