1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @key aot
  27  * @modules jdk.aot/jdk.tools.jaotc
  28  *          jdk.aot/jdk.tools.jaotc.collect
  29  * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSearchTest
  30  */
  31 
  32 package jdk.tools.jaotc.test.collect;
  33 
  34 
  35 import jdk.tools.jaotc.LoadedClass;
  36 import jdk.tools.jaotc.collect.*;
  37 import org.junit.Assert;
  38 import org.junit.Test;
  39 
  40 import java.util.ArrayList;
  41 import java.util.HashSet;
  42 import java.util.List;
  43 import java.util.Set;
  44 import java.util.function.BiConsumer;
  45 import java.util.function.BiFunction;
  46 
  47 public class ClassSearchTest {
  48     @Test(expected = InternalError.class)
  49     public void itShouldThrowExceptionIfNoProvidersAvailable() {
  50         ClassSearch target = new ClassSearch();
  51         SearchPath searchPath = new SearchPath();
  52         target.search(list(new SearchFor("foo")), searchPath);
  53     }
  54 
  55     @Test
  56     public void itShouldFindAProviderForEachEntry() {
  57         Set<String> searched = new HashSet<>();
  58         ClassSearch target = new ClassSearch();
  59         target.addProvider(provider("", (name, searchPath) -> {
  60                 searched.add(name);
  61                 return new NoopSource();
  62         }));
  63         target.search(searchForList("foo", "bar", "foobar"), null);
  64         Assert.assertEquals(hashset("foo", "bar", "foobar"), searched);
  65     }
  66 
  67     private SourceProvider provider(String supports, BiFunction<String, SearchPath, ClassSource> fn) {
  68         return new SourceProvider() {
  69             @Override
  70             public ClassSource findSource(String name, SearchPath searchPath) {
  71                 return fn.apply(name, searchPath);
  72             }
  73 
  74             @Override
  75             public boolean supports(String type) {
  76                 return supports.equals(type);
  77             }
  78         };
  79     }
  80 
  81     @Test
  82     public void itShouldOnlySearchSupportedProvidersForKnownType() {
  83         Set<String> visited = new HashSet<>();
  84         ClassSearch target = new ClassSearch();
  85 
  86         target.addProvider(provider("jar", (name, searchPath) -> {
  87             visited.add("jar");
  88             return null;
  89         }));
  90 
  91         target.addProvider(provider("dir", (name, searchPath) -> {
  92             visited.add("dir");
  93             return null;
  94         }));
  95 
  96         try {
  97             target.search(list(new SearchFor("some", "dir")), null);
  98         } catch (InternalError e) {
  99             // throws because no provider gives a source
 100         }
 101 
 102         Assert.assertEquals(hashset("dir"), visited);
 103     }
 104 
 105     @Test(expected = InternalError.class)
 106     public void itShouldThrowErrorIfMultipleSourcesAreAvailable() {
 107         ClassSearch target = new ClassSearch();
 108         target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
 109         target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
 110 
 111         target.search(searchForList("somethign"), null);
 112     }
 113 
 114     @Test
 115     public void itShouldSearchAllProvidersForUnknownType() {
 116         Set<String> visited = new HashSet<>();
 117         ClassSearch target = new ClassSearch();
 118         target.addProvider(provider("", (name, searchPath) -> {
 119             visited.add("1");
 120             return null;
 121         }));
 122         target.addProvider(provider("", (name, searchPath) -> {
 123             visited.add("2");
 124             return null;
 125         }));
 126 
 127         try {
 128             target.search(searchForList("foo"), null);
 129         } catch (InternalError e) {
 130             // throws because no provider gives a source
 131         }
 132 
 133         Assert.assertEquals(hashset("1", "2"), visited);
 134     }
 135 
 136     @Test
 137     public void itShouldTryToLoadSaidClassFromClassLoader() {
 138         Set<String> loaded = new HashSet<>();
 139 
 140         ClassSearch target = new ClassSearch();
 141         target.addProvider(new SourceProvider() {
 142             @Override
 143             public boolean supports(String type) {
 144                 return true;
 145             }
 146 
 147             @Override
 148             public ClassSource findSource(String name, SearchPath searchPath) {
 149                 return new ClassSource() {
 150                     @Override
 151                     public void eachClass(BiConsumer<String, ClassLoader> consumer) {
 152                         consumer.accept("foo.Bar", new ClassLoader() {
 153                             @Override
 154                             public Class<?> loadClass(String name) throws ClassNotFoundException {
 155                                 loaded.add(name);
 156                                 return null;
 157                             }
 158                         });
 159                     }
 160                 };
 161             }
 162         });
 163 
 164         java.util.List<LoadedClass> search = target.search(searchForList("/tmp/something"), null);
 165         Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search);
 166     }
 167 
 168     @Test(expected = InternalError.class)
 169     public void itShouldThrowInternalErrorWhenClassLoaderFails() {
 170         ClassLoader classLoader = new ClassLoader() {
 171             @Override
 172             public Class<?> loadClass(String name1) throws ClassNotFoundException {
 173                 throw new ClassNotFoundException("failed to find " + name1);
 174             }
 175         };
 176 
 177         ClassSearch target = new ClassSearch();
 178         target.addProvider(provider("", (name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)));
 179         target.search(searchForList("foobar"), null);
 180     }
 181 
 182     private List<SearchFor> searchForList(String... entries) {
 183         List<SearchFor> list = new ArrayList<>();
 184         for (String entry : entries) {
 185             list.add(new SearchFor(entry));
 186         }
 187         return list;
 188     }
 189 
 190     private <T> List<T> list(T... entries) {
 191         List<T> list = new ArrayList<T>();
 192         for (T entry : entries) {
 193             list.add(entry);
 194         }
 195         return list;
 196     }
 197 
 198     private <T> Set<T> hashset(T... entries) {
 199         Set<T> set = new HashSet<T>();
 200         for (T entry : entries) {
 201             set.add(entry);
 202         }
 203         return set;
 204     }
 205 
 206     private static class NoopSource implements ClassSource {
 207         @Override
 208         public void eachClass(BiConsumer<String, ClassLoader> consumer) {
 209         }
 210     }
 211 }