/* * Copyright (C) 2012 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.reflect; import static org.truth0.Truth.ASSERT; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.google.common.reflect.ClassPath.ClassInfo; import com.google.common.reflect.subpackage.ClassInSubPackage; import com.google.common.testing.EqualsTester; import com.google.common.testing.NullPointerTester; import junit.framework.TestCase; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.Set; import java.util.jar.Manifest; /** * Functional tests of {@link ClassPath}. */ public class ClassPathTest extends TestCase { public void testGetClasses() throws Exception { Set<String> names = Sets.newHashSet(); Set<String> strings = Sets.newHashSet(); Set<Class<?>> classes = Sets.newHashSet(); Set<String> packageNames = Sets.newHashSet(); Set<String> simpleNames = Sets.newHashSet(); ClassPath classpath = ClassPath.from(getClass().getClassLoader()); for (ClassInfo classInfo : classpath.getTopLevelClasses(ClassPathTest.class.getPackage().getName())) { names.add(classInfo.getName()); strings.add(classInfo.toString()); classes.add(classInfo.load()); packageNames.add(classInfo.getPackageName()); simpleNames.add(classInfo.getSimpleName()); } ASSERT.that(names).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName()); ASSERT.that(strings).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName()); ASSERT.that(classes).has().allOf(ClassPath.class, ClassPathTest.class); ASSERT.that(packageNames).has().item(ClassPath.class.getPackage().getName()); ASSERT.that(simpleNames).has().allOf("ClassPath", "ClassPathTest"); assertFalse(classes.contains(ClassInSubPackage.class)); } public void testGetClassesRecursive() throws Exception { Set<Class<?>> classes = Sets.newHashSet(); ClassPath classpath = ClassPath.from(ClassPathTest.class.getClassLoader()); for (ClassInfo classInfo : classpath.getTopLevelClassesRecursive(ClassPathTest.class.getPackage().getName())) { classes.add(classInfo.load()); } ASSERT.that(classes).has().allOf(ClassPathTest.class, ClassInSubPackage.class); } public void testGetClasses_diamond() throws Exception { ClassLoader parent = ClassPathTest.class.getClassLoader(); ClassLoader sub1 = new ClassLoader(parent) {}; ClassLoader sub2 = new ClassLoader(parent) {}; assertEquals(findClass(ClassPath.from(sub1).getTopLevelClasses(), ClassPathTest.class), findClass(ClassPath.from(sub2).getTopLevelClasses(), ClassPathTest.class)); } public void testClassInfo() { new EqualsTester() .addEqualityGroup(classInfo(ClassPathTest.class), classInfo(ClassPathTest.class)) .addEqualityGroup(classInfo(Test.class), classInfo(Test.class, getClass().getClassLoader())) .testEquals(); } public void testClassPathEntries_emptyURLClassLoader_noParent() { ASSERT.that(ClassPath.getClassPathEntries(new URLClassLoader(new URL[0], null)).keySet()) .isEmpty(); } public void testClassPathEntries_URLClassLoader_noParent() throws Exception { URL url1 = new URL("file:/a"); URL url2 = new URL("file:/b"); URLClassLoader classloader = new URLClassLoader(new URL[] {url1, url2}, null); assertEquals( ImmutableMap.of(url1.toURI(), classloader, url2.toURI(), classloader), ClassPath.getClassPathEntries(classloader)); } public void testClassPathEntries_URLClassLoader_withParent() throws Exception { URL url1 = new URL("file:/a"); URL url2 = new URL("file:/b"); URLClassLoader parent = new URLClassLoader(new URL[] {url1}, null); URLClassLoader child = new URLClassLoader(new URL[] {url2}, parent) {}; ImmutableMap<URI, ClassLoader> classPathEntries = ClassPath.getClassPathEntries(child); assertEquals(ImmutableMap.of(url1.toURI(), parent, url2.toURI(), child), classPathEntries); ASSERT.that(classPathEntries.keySet()).has().allOf(url1.toURI(), url2.toURI()).inOrder(); } public void testClassPathEntries_duplicateUri_parentWins() throws Exception { URL url = new URL("file:/a"); URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); URLClassLoader child = new URLClassLoader(new URL[] {url}, parent) {}; assertEquals(ImmutableMap.of(url.toURI(), parent), ClassPath.getClassPathEntries(child)); } public void testClassPathEntries_notURLClassLoader_noParent() { ASSERT.that(ClassPath.getClassPathEntries(new ClassLoader(null) {}).keySet()).isEmpty(); } public void testClassPathEntries_notURLClassLoader_withParent() throws Exception { URL url = new URL("file:/a"); URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); assertEquals( ImmutableMap.of(url.toURI(), parent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } public void testClassPathEntries_notURLClassLoader_withParentAndGrandParent() throws Exception { URL url1 = new URL("file:/a"); URL url2 = new URL("file:/b"); URLClassLoader grandParent = new URLClassLoader(new URL[] {url1}, null); URLClassLoader parent = new URLClassLoader(new URL[] {url2}, grandParent); assertEquals( ImmutableMap.of(url1.toURI(), grandParent, url2.toURI(), parent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } public void testClassPathEntries_notURLClassLoader_withGrandParent() throws Exception { URL url = new URL("file:/a"); URLClassLoader grandParent = new URLClassLoader(new URL[] {url}, null); ClassLoader parent = new ClassLoader(grandParent) {}; assertEquals( ImmutableMap.of(url.toURI(), grandParent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } public void testReadClassesFromFile_fileNotExists() throws IOException { ClassLoader classLoader = ClassPathTest.class.getClassLoader(); ASSERT.that(ClassPath.readClassesFrom(new File("no/such/file/anywhere"), classLoader)) .isEmpty(); } public void testGetClassPathEntry() throws URISyntaxException { assertEquals(URI.create("file:/usr/test/dep.jar"), ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "file:/usr/test/dep.jar")); assertEquals(URI.create("file:/home/build/a.jar"), ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "a.jar")); assertEquals(URI.create("file:/home/build/x/y/z"), ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z")); assertEquals(URI.create("file:/home/build/x/y/z.jar"), ClassPath.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z.jar")); } public void testGetClassPathFromManifest_nullManifest() { ASSERT.that(ClassPath.getClassPathFromManifest(new File("some.jar"), null)).isEmpty(); } public void testGetClassPathFromManifest_noClassPath() throws IOException { File jarFile = new File("base.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest(""))) .isEmpty(); } public void testGetClassPathFromManifest_emptyClassPath() throws IOException { File jarFile = new File("base.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifestClasspath(""))) .isEmpty(); } public void testGetClassPathFromManifest_badClassPath() throws IOException { File jarFile = new File("base.jar"); Manifest manifest = manifestClasspath("an_invalid^path"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .isEmpty(); } public void testGetClassPathFromManifest_relativeDirectory() throws IOException { File jarFile = new File("base/some.jar"); // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("with/relative/dir"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("base/with/relative/dir").toURI()).inOrder(); } public void testGetClassPathFromManifest_relativeJar() throws IOException { File jarFile = new File("base/some.jar"); // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("with/relative.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("base/with/relative.jar").toURI()).inOrder(); } public void testGetClassPathFromManifest_jarInCurrentDirectory() throws IOException { File jarFile = new File("base/some.jar"); // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("current.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("base/current.jar").toURI()).inOrder(); } public void testGetClassPathFromManifest_absoluteDirectory() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("file:/with/absolute/dir"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("/with/absolute/dir").toURI()).inOrder(); } public void testGetClassPathFromManifest_absoluteJar() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("file:/with/absolute.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("/with/absolute.jar").toURI()).inOrder(); } public void testGetClassPathFromManifest_multiplePaths() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("file:/with/absolute.jar relative.jar relative/dir"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf( new File("/with/absolute.jar").toURI(), new File("base/relative.jar").toURI(), new File("base/relative/dir").toURI()) .inOrder(); } public void testGetClassPathFromManifest_leadingBlanks() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath(" relative.jar"); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("base/relative.jar").toURI()).inOrder(); } public void testGetClassPathFromManifest_trailingBlanks() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("relative.jar "); ASSERT.that(ClassPath.getClassPathFromManifest(jarFile, manifest)) .has().allOf(new File("base/relative.jar").toURI()).inOrder(); } public void testGetClassName() { assertEquals("Abc", ClassPath.getClassName("Abc.class")); } public void testIsTopLevelClassName() { assertTrue(ClassPath.isTopLevelClassFile(ClassPathTest.class.getName() + ".class")); assertFalse(ClassPath.isTopLevelClassFile(ClassPathTest.class.getName())); assertFalse(ClassPath.isTopLevelClassFile(Nested.class.getName() + ".class")); } public void testGetSimpleName() { assertEquals("Foo", new ClassPath.ClassInfo("Foo", getClass().getClassLoader()).getSimpleName()); assertEquals("Foo", new ClassPath.ClassInfo("a.b.Foo", getClass().getClassLoader()).getSimpleName()); } public void testGetPackageName() { assertEquals("", new ClassPath.ClassInfo("Foo", getClass().getClassLoader()).getPackageName()); assertEquals("a.b", new ClassPath.ClassInfo("a.b.Foo", getClass().getClassLoader()).getPackageName()); } private static class Nested {} public void testNulls() throws IOException { new NullPointerTester().testAllPublicStaticMethods(ClassPath.class); new NullPointerTester() .testAllPublicInstanceMethods(ClassPath.from(getClass().getClassLoader())); } private static ClassPath.ClassInfo findClass( Iterable<ClassPath.ClassInfo> classes, Class<?> cls) { for (ClassPath.ClassInfo classInfo : classes) { if (classInfo.getName().equals(cls.getName())) { return classInfo; } } throw new AssertionError("failed to find " + cls); } private static ClassPath.ClassInfo classInfo(Class<?> cls) { return classInfo(cls, cls.getClassLoader()); } private static ClassPath.ClassInfo classInfo(Class<?> cls, ClassLoader classLoader) { return new ClassPath.ClassInfo(cls.getName(), classLoader); } private static Manifest manifestClasspath(String classpath) throws IOException { return manifest("Class-Path: " + classpath + "\n"); } private static Manifest manifest(String content) throws IOException { InputStream in = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII)); Manifest manifest = new Manifest(); manifest.read(in); return manifest; } }