17dd252788645e940eada959bdde927426e2531c9Paul Duffin/*
27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2012 The Guava Authors
37dd252788645e940eada959bdde927426e2531c9Paul Duffin *
47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License.
67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at
77dd252788645e940eada959bdde927426e2531c9Paul Duffin *
87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
97dd252788645e940eada959bdde927426e2531c9Paul Duffin *
107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software
117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and
147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License.
157dd252788645e940eada959bdde927426e2531c9Paul Duffin */
167dd252788645e940eada959bdde927426e2531c9Paul Duffin
177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.reflect;
187dd252788645e940eada959bdde927426e2531c9Paul Duffin
197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static org.truth0.Truth.ASSERT;
207dd252788645e940eada959bdde927426e2531c9Paul Duffin
217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.base.Charsets;
227dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.ImmutableMap;
237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Maps;
247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Sets;
250888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.io.Closer;
260888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.io.Resources;
277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.reflect.ClassPath.ClassInfo;
287dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.reflect.ClassPath.ResourceInfo;
297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.reflect.subpackage.ClassInSubPackage;
307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.testing.EqualsTester;
317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.testing.NullPointerTester;
327dd252788645e940eada959bdde927426e2531c9Paul Duffin
337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport junit.framework.TestCase;
347dd252788645e940eada959bdde927426e2531c9Paul Duffinimport org.junit.Test;
357dd252788645e940eada959bdde927426e2531c9Paul Duffin
367dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.ByteArrayInputStream;
377dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.File;
380888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.io.FileOutputStream;
397dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.IOException;
407dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.InputStream;
417dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URI;
427dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URISyntaxException;
437dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URL;
447dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URLClassLoader;
457dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Map;
467dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Set;
470888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.jar.Attributes;
480888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.jar.JarFile;
490888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.jar.JarOutputStream;
507dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.jar.Manifest;
510888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.zip.ZipEntry;
527dd252788645e940eada959bdde927426e2531c9Paul Duffin
537dd252788645e940eada959bdde927426e2531c9Paul Duffin/**
547dd252788645e940eada959bdde927426e2531c9Paul Duffin * Functional tests of {@link ClassPath}.
557dd252788645e940eada959bdde927426e2531c9Paul Duffin */
567dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic class ClassPathTest extends TestCase {
577dd252788645e940eada959bdde927426e2531c9Paul Duffin
587dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetResources() throws Exception {
597dd252788645e940eada959bdde927426e2531c9Paul Duffin    Map<String, ResourceInfo> byName = Maps.newHashMap();
607dd252788645e940eada959bdde927426e2531c9Paul Duffin    Map<String, ResourceInfo> byToString = Maps.newHashMap();
617dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassPath classpath = ClassPath.from(getClass().getClassLoader());
627dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (ResourceInfo resource : classpath.getResources()) {
630888a09821a98ac0680fad765217302858e70fa4Paul Duffin      ASSERT.that(resource.getResourceName()).isNotEqualTo(JarFile.MANIFEST_NAME);
640888a09821a98ac0680fad765217302858e70fa4Paul Duffin      ASSERT.that(resource.toString()).isNotEqualTo(JarFile.MANIFEST_NAME);
657dd252788645e940eada959bdde927426e2531c9Paul Duffin      byName.put(resource.getResourceName(), resource);
667dd252788645e940eada959bdde927426e2531c9Paul Duffin      byToString.put(resource.toString(), resource);
677dd252788645e940eada959bdde927426e2531c9Paul Duffin      // TODO: This will fail on maven resources in the classes directory on a mac.
687dd252788645e940eada959bdde927426e2531c9Paul Duffin      // assertNotNull(resource.url());
697dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
707dd252788645e940eada959bdde927426e2531c9Paul Duffin    String testResourceName = "com/google/common/reflect/test.txt";
710888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(byName.keySet()).has().allOf(
727dd252788645e940eada959bdde927426e2531c9Paul Duffin        "com/google/common/reflect/ClassPath.class",
737dd252788645e940eada959bdde927426e2531c9Paul Duffin        "com/google/common/reflect/ClassPathTest.class",
747dd252788645e940eada959bdde927426e2531c9Paul Duffin        "com/google/common/reflect/ClassPathTest$Nested.class",
757dd252788645e940eada959bdde927426e2531c9Paul Duffin        testResourceName);
760888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(byToString.keySet()).has().allOf(
777dd252788645e940eada959bdde927426e2531c9Paul Duffin        "com.google.common.reflect.ClassPath",
787dd252788645e940eada959bdde927426e2531c9Paul Duffin        "com.google.common.reflect.ClassPathTest",
790888a09821a98ac0680fad765217302858e70fa4Paul Duffin        "com.google.common.reflect.ClassPathTest$Nested",
807dd252788645e940eada959bdde927426e2531c9Paul Duffin        testResourceName);
817dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(getClass().getClassLoader().getResource(testResourceName),
827dd252788645e940eada959bdde927426e2531c9Paul Duffin        byName.get("com/google/common/reflect/test.txt").url());
837dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
847dd252788645e940eada959bdde927426e2531c9Paul Duffin
850888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testGetAllClasses() throws Exception {
860888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Set<String> names = Sets.newHashSet();
870888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Set<String> strings = Sets.newHashSet();
880888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Set<Class<?>> classes = Sets.newHashSet();
890888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Set<String> packageNames = Sets.newHashSet();
900888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Set<String> simpleNames = Sets.newHashSet();
910888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ClassPath classpath = ClassPath.from(getClass().getClassLoader());
920888a09821a98ac0680fad765217302858e70fa4Paul Duffin    for (ClassInfo classInfo : classpath.getAllClasses()) {
930888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (!classInfo.getPackageName().equals(ClassPathTest.class.getPackage().getName())) {
940888a09821a98ac0680fad765217302858e70fa4Paul Duffin        continue;
950888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
960888a09821a98ac0680fad765217302858e70fa4Paul Duffin      names.add(classInfo.getName());
970888a09821a98ac0680fad765217302858e70fa4Paul Duffin      strings.add(classInfo.toString());
980888a09821a98ac0680fad765217302858e70fa4Paul Duffin      classes.add(classInfo.load());
990888a09821a98ac0680fad765217302858e70fa4Paul Duffin      packageNames.add(classInfo.getPackageName());
1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin      simpleNames.add(classInfo.getSimpleName());
1010888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
1020888a09821a98ac0680fad765217302858e70fa4Paul Duffin    class LocalClass {}
1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Class<?> anonymousClass = new Object() {}.getClass();
1040888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(names).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
1050888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.class.getName(), ClassPathTest.class.getName());
1060888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(strings).has().allOf(anonymousClass.getName(), LocalClass.class.getName(),
1070888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.class.getName(), ClassPathTest.class.getName());
1080888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(classes).has().allOf(anonymousClass, LocalClass.class, ClassPath.class,
1090888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPathTest.class);
1100888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(packageNames).has().exactly(ClassPath.class.getPackage().getName());
1110888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(simpleNames).has().allOf("", "Local", "ClassPath", "ClassPathTest");
1120888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
1130888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testGetTopLevelClasses() throws Exception {
1157dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<String> names = Sets.newHashSet();
1167dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<String> strings = Sets.newHashSet();
1177dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<Class<?>> classes = Sets.newHashSet();
1187dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<String> packageNames = Sets.newHashSet();
1197dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<String> simpleNames = Sets.newHashSet();
1207dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassPath classpath = ClassPath.from(getClass().getClassLoader());
1217dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (ClassInfo classInfo
1227dd252788645e940eada959bdde927426e2531c9Paul Duffin        : classpath.getTopLevelClasses(ClassPathTest.class.getPackage().getName())) {
1237dd252788645e940eada959bdde927426e2531c9Paul Duffin      names.add(classInfo.getName());
1247dd252788645e940eada959bdde927426e2531c9Paul Duffin      strings.add(classInfo.toString());
1257dd252788645e940eada959bdde927426e2531c9Paul Duffin      classes.add(classInfo.load());
1267dd252788645e940eada959bdde927426e2531c9Paul Duffin      packageNames.add(classInfo.getPackageName());
1277dd252788645e940eada959bdde927426e2531c9Paul Duffin      simpleNames.add(classInfo.getSimpleName());
1287dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1290888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(names).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
1300888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(strings).has().allOf(ClassPath.class.getName(), ClassPathTest.class.getName());
1310888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(classes).has().allOf(ClassPath.class, ClassPathTest.class);
1320888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(packageNames).has().item(ClassPath.class.getPackage().getName());
1330888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(simpleNames).has().allOf("ClassPath", "ClassPathTest");
1347dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertFalse(classes.contains(ClassInSubPackage.class));
1357dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1367dd252788645e940eada959bdde927426e2531c9Paul Duffin
1370888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testGetTopLevelClassesRecursive() throws Exception {
1387dd252788645e940eada959bdde927426e2531c9Paul Duffin    Set<Class<?>> classes = Sets.newHashSet();
1397dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassPath classpath = ClassPath.from(ClassPathTest.class.getClassLoader());
1407dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (ClassInfo classInfo
1417dd252788645e940eada959bdde927426e2531c9Paul Duffin        : classpath.getTopLevelClassesRecursive(ClassPathTest.class.getPackage().getName())) {
1420888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (classInfo.getName().contains("ClassPathTest")) {
1430888a09821a98ac0680fad765217302858e70fa4Paul Duffin        System.err.println("");
1440888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
1457dd252788645e940eada959bdde927426e2531c9Paul Duffin      classes.add(classInfo.load());
1467dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1470888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(classes).has().allOf(ClassPathTest.class, ClassInSubPackage.class);
1487dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1497dd252788645e940eada959bdde927426e2531c9Paul Duffin
1500888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testGetTopLevelClasses_diamond() throws Exception {
1517dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader parent = ClassPathTest.class.getClassLoader();
1527dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader sub1 = new ClassLoader(parent) {};
1537dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader sub2 = new ClassLoader(parent) {};
1547dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(findClass(ClassPath.from(sub1).getTopLevelClasses(), ClassPathTest.class),
1557dd252788645e940eada959bdde927426e2531c9Paul Duffin        findClass(ClassPath.from(sub2).getTopLevelClasses(), ClassPathTest.class));
1567dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1577dd252788645e940eada959bdde927426e2531c9Paul Duffin
1587dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testEquals() {
1597dd252788645e940eada959bdde927426e2531c9Paul Duffin    new EqualsTester()
1607dd252788645e940eada959bdde927426e2531c9Paul Duffin        .addEqualityGroup(classInfo(ClassPathTest.class), classInfo(ClassPathTest.class))
1617dd252788645e940eada959bdde927426e2531c9Paul Duffin        .addEqualityGroup(classInfo(Test.class), classInfo(Test.class, getClass().getClassLoader()))
1627dd252788645e940eada959bdde927426e2531c9Paul Duffin        .addEqualityGroup(
1637dd252788645e940eada959bdde927426e2531c9Paul Duffin            new ResourceInfo("a/b/c.txt", getClass().getClassLoader()),
1647dd252788645e940eada959bdde927426e2531c9Paul Duffin            new ResourceInfo("a/b/c.txt", getClass().getClassLoader()))
1657dd252788645e940eada959bdde927426e2531c9Paul Duffin        .addEqualityGroup(
1667dd252788645e940eada959bdde927426e2531c9Paul Duffin            new ResourceInfo("x.txt", getClass().getClassLoader()))
1677dd252788645e940eada959bdde927426e2531c9Paul Duffin        .testEquals();
1687dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1697dd252788645e940eada959bdde927426e2531c9Paul Duffin
1707dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_emptyURLClassLoader_noParent() {
1710888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.getClassPathEntries(new URLClassLoader(new URL[0], null)).keySet())
1727dd252788645e940eada959bdde927426e2531c9Paul Duffin        .isEmpty();
1737dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1747dd252788645e940eada959bdde927426e2531c9Paul Duffin
1757dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_URLClassLoader_noParent() throws Exception {
1767dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url1 = new URL("file:/a");
1777dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url2 = new URL("file:/b");
1787dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader classloader = new URLClassLoader(new URL[] {url1, url2}, null);
1797dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(
1807dd252788645e940eada959bdde927426e2531c9Paul Duffin        ImmutableMap.of(url1.toURI(), classloader, url2.toURI(), classloader),
1817dd252788645e940eada959bdde927426e2531c9Paul Duffin        ClassPath.getClassPathEntries(classloader));
1827dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1837dd252788645e940eada959bdde927426e2531c9Paul Duffin
1847dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_URLClassLoader_withParent() throws Exception {
1857dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url1 = new URL("file:/a");
1867dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url2 = new URL("file:/b");
1877dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader parent = new URLClassLoader(new URL[] {url1}, null);
1887dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader child = new URLClassLoader(new URL[] {url2}, parent) {};
1897dd252788645e940eada959bdde927426e2531c9Paul Duffin    ImmutableMap<URI, ClassLoader> classPathEntries = ClassPath.getClassPathEntries(child);
1907dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(ImmutableMap.of(url1.toURI(), parent, url2.toURI(), child),  classPathEntries);
1910888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(classPathEntries.keySet()).has().exactly(url1.toURI(), url2.toURI()).inOrder();
1927dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1937dd252788645e940eada959bdde927426e2531c9Paul Duffin
1947dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_duplicateUri_parentWins() throws Exception {
1957dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url = new URL("file:/a");
1967dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader parent = new URLClassLoader(new URL[] {url}, null);
1977dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader child = new URLClassLoader(new URL[] {url}, parent) {};
1987dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(ImmutableMap.of(url.toURI(), parent), ClassPath.getClassPathEntries(child));
1997dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2007dd252788645e940eada959bdde927426e2531c9Paul Duffin
2017dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_notURLClassLoader_noParent() {
2020888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.getClassPathEntries(new ClassLoader(null) {}).keySet()).isEmpty();
2037dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2047dd252788645e940eada959bdde927426e2531c9Paul Duffin
2057dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_notURLClassLoader_withParent() throws Exception {
2067dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url = new URL("file:/a");
2077dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader parent = new URLClassLoader(new URL[] {url}, null);
2087dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(
2097dd252788645e940eada959bdde927426e2531c9Paul Duffin        ImmutableMap.of(url.toURI(), parent),
2107dd252788645e940eada959bdde927426e2531c9Paul Duffin        ClassPath.getClassPathEntries(new ClassLoader(parent) {}));
2117dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2127dd252788645e940eada959bdde927426e2531c9Paul Duffin
2137dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_notURLClassLoader_withParentAndGrandParent() throws Exception {
2147dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url1 = new URL("file:/a");
2157dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url2 = new URL("file:/b");
2167dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader grandParent = new URLClassLoader(new URL[] {url1}, null);
2177dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader parent = new URLClassLoader(new URL[] {url2}, grandParent);
2187dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(
2197dd252788645e940eada959bdde927426e2531c9Paul Duffin        ImmutableMap.of(url1.toURI(), grandParent, url2.toURI(), parent),
2207dd252788645e940eada959bdde927426e2531c9Paul Duffin        ClassPath.getClassPathEntries(new ClassLoader(parent) {}));
2217dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2227dd252788645e940eada959bdde927426e2531c9Paul Duffin
2237dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testClassPathEntries_notURLClassLoader_withGrandParent() throws Exception {
2247dd252788645e940eada959bdde927426e2531c9Paul Duffin    URL url = new URL("file:/a");
2257dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader grandParent = new URLClassLoader(new URL[] {url}, null);
2267dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader parent = new ClassLoader(grandParent) {};
2277dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(
2287dd252788645e940eada959bdde927426e2531c9Paul Duffin        ImmutableMap.of(url.toURI(), grandParent),
2297dd252788645e940eada959bdde927426e2531c9Paul Duffin        ClassPath.getClassPathEntries(new ClassLoader(parent) {}));
2307dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2317dd252788645e940eada959bdde927426e2531c9Paul Duffin
2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testScan_classPathCycle() throws IOException {
2330888a09821a98ac0680fad765217302858e70fa4Paul Duffin    File jarFile = File.createTempFile("with_circular_class_path", ".jar");
2340888a09821a98ac0680fad765217302858e70fa4Paul Duffin    try {
2350888a09821a98ac0680fad765217302858e70fa4Paul Duffin      writeSelfReferencingJarFile(jarFile, "test.txt");
2360888a09821a98ac0680fad765217302858e70fa4Paul Duffin      ClassPath.Scanner scanner = new ClassPath.Scanner();
2370888a09821a98ac0680fad765217302858e70fa4Paul Duffin      scanner.scan(jarFile.toURI(), ClassPathTest.class.getClassLoader());
2380888a09821a98ac0680fad765217302858e70fa4Paul Duffin      assertEquals(1, scanner.getResources().size());
2390888a09821a98ac0680fad765217302858e70fa4Paul Duffin    } finally {
2400888a09821a98ac0680fad765217302858e70fa4Paul Duffin      jarFile.delete();
2410888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
2420888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
2430888a09821a98ac0680fad765217302858e70fa4Paul Duffin
2440888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testScanFromFile_fileNotExists() throws IOException {
2457dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader classLoader = ClassPathTest.class.getClassLoader();
2460888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ClassPath.Scanner scanner = new ClassPath.Scanner();
2470888a09821a98ac0680fad765217302858e70fa4Paul Duffin    scanner.scanFrom(new File("no/such/file/anywhere"), classLoader);
2480888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(scanner.getResources()).isEmpty();
2497dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2507dd252788645e940eada959bdde927426e2531c9Paul Duffin
2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testScanFromFile_notJarFile() throws IOException {
2527dd252788645e940eada959bdde927426e2531c9Paul Duffin    ClassLoader classLoader = ClassPathTest.class.getClassLoader();
2537dd252788645e940eada959bdde927426e2531c9Paul Duffin    File notJar = File.createTempFile("not_a_jar", "txt");
2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ClassPath.Scanner scanner = new ClassPath.Scanner();
2557dd252788645e940eada959bdde927426e2531c9Paul Duffin    try {
2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin      scanner.scanFrom(notJar, classLoader);
2577dd252788645e940eada959bdde927426e2531c9Paul Duffin    } finally {
2587dd252788645e940eada959bdde927426e2531c9Paul Duffin      notJar.delete();
2597dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(scanner.getResources()).isEmpty();
2617dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2627dd252788645e940eada959bdde927426e2531c9Paul Duffin
2637dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathEntry() throws URISyntaxException {
2647dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(URI.create("file:/usr/test/dep.jar"),
2650888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.Scanner.getClassPathEntry(
2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin            new File("/home/build/outer.jar"), "file:/usr/test/dep.jar"));
2677dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(URI.create("file:/home/build/a.jar"),
2680888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "a.jar"));
2697dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(URI.create("file:/home/build/x/y/z"),
2700888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z"));
2717dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(URI.create("file:/home/build/x/y/z.jar"),
2720888a09821a98ac0680fad765217302858e70fa4Paul Duffin        ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z.jar"));
2737dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2747dd252788645e940eada959bdde927426e2531c9Paul Duffin
2757dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_nullManifest() {
2760888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(new File("some.jar"), null)).isEmpty();
2777dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2787dd252788645e940eada959bdde927426e2531c9Paul Duffin
2797dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_noClassPath() throws IOException {
2807dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base.jar");
2810888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest("")))
2827dd252788645e940eada959bdde927426e2531c9Paul Duffin        .isEmpty();
2837dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2847dd252788645e940eada959bdde927426e2531c9Paul Duffin
2857dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_emptyClassPath() throws IOException {
2867dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base.jar");
2870888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifestClasspath("")))
2887dd252788645e940eada959bdde927426e2531c9Paul Duffin        .isEmpty();
2897dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2907dd252788645e940eada959bdde927426e2531c9Paul Duffin
2917dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_badClassPath() throws IOException {
2927dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base.jar");
2937dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("an_invalid^path");
2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
2957dd252788645e940eada959bdde927426e2531c9Paul Duffin        .isEmpty();
2967dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2977dd252788645e940eada959bdde927426e2531c9Paul Duffin
2987dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_relativeDirectory() throws IOException {
2997dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3007dd252788645e940eada959bdde927426e2531c9Paul Duffin    // with/relative/directory is the Class-Path value in the mf file.
3017dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("with/relative/dir");
3020888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3030888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("base/with/relative/dir").toURI()).inOrder();
3047dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3057dd252788645e940eada959bdde927426e2531c9Paul Duffin
3067dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_relativeJar() throws IOException {
3077dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3087dd252788645e940eada959bdde927426e2531c9Paul Duffin    // with/relative/directory is the Class-Path value in the mf file.
3097dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("with/relative.jar");
3100888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3110888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("base/with/relative.jar").toURI()).inOrder();
3127dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3137dd252788645e940eada959bdde927426e2531c9Paul Duffin
3147dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_jarInCurrentDirectory() throws IOException {
3157dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3167dd252788645e940eada959bdde927426e2531c9Paul Duffin    // with/relative/directory is the Class-Path value in the mf file.
3177dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("current.jar");
3180888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("base/current.jar").toURI()).inOrder();
3207dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3217dd252788645e940eada959bdde927426e2531c9Paul Duffin
3227dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_absoluteDirectory() throws IOException {
3237dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3247dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("file:/with/absolute/dir");
3250888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3260888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("/with/absolute/dir").toURI()).inOrder();
3277dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3287dd252788645e940eada959bdde927426e2531c9Paul Duffin
3297dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_absoluteJar() throws IOException {
3307dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3317dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("file:/with/absolute.jar");
3320888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3330888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("/with/absolute.jar").toURI()).inOrder();
3347dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3357dd252788645e940eada959bdde927426e2531c9Paul Duffin
3367dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_multiplePaths() throws IOException {
3377dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3387dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("file:/with/absolute.jar relative.jar  relative/dir");
3390888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3400888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(
3417dd252788645e940eada959bdde927426e2531c9Paul Duffin            new File("/with/absolute.jar").toURI(),
3427dd252788645e940eada959bdde927426e2531c9Paul Duffin            new File("base/relative.jar").toURI(),
3437dd252788645e940eada959bdde927426e2531c9Paul Duffin            new File("base/relative/dir").toURI())
3447dd252788645e940eada959bdde927426e2531c9Paul Duffin        .inOrder();
3457dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3467dd252788645e940eada959bdde927426e2531c9Paul Duffin
3477dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_leadingBlanks() throws IOException {
3487dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3497dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath(" relative.jar");
3500888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3510888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("base/relative.jar").toURI()).inOrder();
3527dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3537dd252788645e940eada959bdde927426e2531c9Paul Duffin
3547dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassPathFromManifest_trailingBlanks() throws IOException {
3557dd252788645e940eada959bdde927426e2531c9Paul Duffin    File jarFile = new File("base/some.jar");
3567dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = manifestClasspath("relative.jar ");
3570888a09821a98ac0680fad765217302858e70fa4Paul Duffin    ASSERT.that(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest))
3580888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .has().exactly(new File("base/relative.jar").toURI()).inOrder();
3597dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3607dd252788645e940eada959bdde927426e2531c9Paul Duffin
3617dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetClassName() {
3627dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals("abc.d.Abc", ClassPath.getClassName("abc/d/Abc.class"));
3637dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3647dd252788645e940eada959bdde927426e2531c9Paul Duffin
3657dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testResourceInfo_of() {
3667dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(ClassInfo.class, resourceInfo(ClassPathTest.class).getClass());
3677dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(ClassInfo.class, resourceInfo(ClassPath.class).getClass());
3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals(ClassInfo.class, resourceInfo(Nested.class).getClass());
3697dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3707dd252788645e940eada959bdde927426e2531c9Paul Duffin
3717dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetSimpleName() {
3727dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals("Foo",
3737dd252788645e940eada959bdde927426e2531c9Paul Duffin        new ClassInfo("Foo.class", getClass().getClassLoader()).getSimpleName());
3747dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals("Foo",
3757dd252788645e940eada959bdde927426e2531c9Paul Duffin        new ClassInfo("a/b/Foo.class", getClass().getClassLoader()).getSimpleName());
3760888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals("Foo",
3770888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new ClassInfo("a/b/Bar$Foo.class", getClass().getClassLoader()).getSimpleName());
3780888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals("",
3790888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new ClassInfo("a/b/Bar$1.class", getClass().getClassLoader()).getSimpleName());
3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals("Foo",
3810888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new ClassInfo("a/b/Bar$Foo.class", getClass().getClassLoader()).getSimpleName());
3820888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals("",
3830888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new ClassInfo("a/b/Bar$1.class", getClass().getClassLoader()).getSimpleName());
3840888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals("Local",
3850888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new ClassInfo("a/b/Bar$1Local.class", getClass().getClassLoader()).getSimpleName());
3860888a09821a98ac0680fad765217302858e70fa4Paul Duffin
3877dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3887dd252788645e940eada959bdde927426e2531c9Paul Duffin
3897dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetPackageName() {
3907dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals("",
3917dd252788645e940eada959bdde927426e2531c9Paul Duffin        new ClassInfo("Foo.class", getClass().getClassLoader()).getPackageName());
3927dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals("a.b",
3937dd252788645e940eada959bdde927426e2531c9Paul Duffin        new ClassInfo("a/b/Foo.class", getClass().getClassLoader()).getPackageName());
3947dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3957dd252788645e940eada959bdde927426e2531c9Paul Duffin
3967dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static class Nested {}
3977dd252788645e940eada959bdde927426e2531c9Paul Duffin
3987dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testNulls() throws IOException {
3997dd252788645e940eada959bdde927426e2531c9Paul Duffin    new NullPointerTester().testAllPublicStaticMethods(ClassPath.class);
4007dd252788645e940eada959bdde927426e2531c9Paul Duffin    new NullPointerTester()
4017dd252788645e940eada959bdde927426e2531c9Paul Duffin        .testAllPublicInstanceMethods(ClassPath.from(getClass().getClassLoader()));
4027dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4037dd252788645e940eada959bdde927426e2531c9Paul Duffin
4047dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static ClassPath.ClassInfo findClass(
4057dd252788645e940eada959bdde927426e2531c9Paul Duffin      Iterable<ClassPath.ClassInfo> classes, Class<?> cls) {
4067dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (ClassPath.ClassInfo classInfo : classes) {
4077dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (classInfo.getName().equals(cls.getName())) {
4087dd252788645e940eada959bdde927426e2531c9Paul Duffin        return classInfo;
4097dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4107dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4117dd252788645e940eada959bdde927426e2531c9Paul Duffin    throw new AssertionError("failed to find " + cls);
4127dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4137dd252788645e940eada959bdde927426e2531c9Paul Duffin
4147dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static ResourceInfo resourceInfo(Class<?> cls) {
4157dd252788645e940eada959bdde927426e2531c9Paul Duffin    return ResourceInfo.of(cls.getName().replace('.', '/') + ".class", cls.getClassLoader());
4167dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4177dd252788645e940eada959bdde927426e2531c9Paul Duffin
4187dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static ClassInfo classInfo(Class<?> cls) {
4197dd252788645e940eada959bdde927426e2531c9Paul Duffin    return classInfo(cls, cls.getClassLoader());
4207dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4217dd252788645e940eada959bdde927426e2531c9Paul Duffin
4227dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static ClassInfo classInfo(Class<?> cls, ClassLoader classLoader) {
4237dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new ClassInfo(cls.getName().replace('.', '/') + ".class", classLoader);
4247dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4257dd252788645e940eada959bdde927426e2531c9Paul Duffin
4267dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static Manifest manifestClasspath(String classpath) throws IOException {
4277dd252788645e940eada959bdde927426e2531c9Paul Duffin    return manifest("Class-Path: " + classpath + "\n");
4287dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4297dd252788645e940eada959bdde927426e2531c9Paul Duffin
4300888a09821a98ac0680fad765217302858e70fa4Paul Duffin  private static void writeSelfReferencingJarFile(File jarFile, String... entries)
4310888a09821a98ac0680fad765217302858e70fa4Paul Duffin      throws IOException {
4320888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Manifest manifest = new Manifest();
4330888a09821a98ac0680fad765217302858e70fa4Paul Duffin    // Without version, the manifest is silently ignored. Ugh!
4340888a09821a98ac0680fad765217302858e70fa4Paul Duffin    manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
4350888a09821a98ac0680fad765217302858e70fa4Paul Duffin    manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, jarFile.getName());
4360888a09821a98ac0680fad765217302858e70fa4Paul Duffin
4370888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Closer closer = Closer.create();
4380888a09821a98ac0680fad765217302858e70fa4Paul Duffin    try {
4390888a09821a98ac0680fad765217302858e70fa4Paul Duffin      FileOutputStream fileOut = closer.register(new FileOutputStream(jarFile));
4400888a09821a98ac0680fad765217302858e70fa4Paul Duffin      JarOutputStream jarOut = closer.register(new JarOutputStream(fileOut));
4410888a09821a98ac0680fad765217302858e70fa4Paul Duffin      for (String entry : entries) {
4420888a09821a98ac0680fad765217302858e70fa4Paul Duffin        jarOut.putNextEntry(new ZipEntry(entry));
4430888a09821a98ac0680fad765217302858e70fa4Paul Duffin        Resources.copy(ClassPathTest.class.getResource(entry), jarOut);
4440888a09821a98ac0680fad765217302858e70fa4Paul Duffin        jarOut.closeEntry();
4450888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
4460888a09821a98ac0680fad765217302858e70fa4Paul Duffin    } catch (Throwable e) {
4470888a09821a98ac0680fad765217302858e70fa4Paul Duffin      throw closer.rethrow(e);
4480888a09821a98ac0680fad765217302858e70fa4Paul Duffin    } finally {
4490888a09821a98ac0680fad765217302858e70fa4Paul Duffin      closer.close();
4500888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
4510888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
4520888a09821a98ac0680fad765217302858e70fa4Paul Duffin
4537dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static Manifest manifest(String content) throws IOException {
4547dd252788645e940eada959bdde927426e2531c9Paul Duffin    InputStream in = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII.name()));
4557dd252788645e940eada959bdde927426e2531c9Paul Duffin    Manifest manifest = new Manifest();
4567dd252788645e940eada959bdde927426e2531c9Paul Duffin    manifest.read(in);
4577dd252788645e940eada959bdde927426e2531c9Paul Duffin    return manifest;
4587dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
4597dd252788645e940eada959bdde927426e2531c9Paul Duffin}
460