3789983e89
Reviewed-by: darcy, ihse
328 lines
15 KiB
Java
328 lines
15 KiB
Java
/*
|
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @summary Tests jdeps -m and -mp options on named modules and unnamed modules
|
|
* @library ../lib
|
|
* @build CompilerUtils JdepsUtil
|
|
* @modules jdk.jdeps/com.sun.tools.jdeps
|
|
* @run testng TransitiveDeps
|
|
*/
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.*;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
import com.sun.tools.jdeps.DepsAnalyzer;
|
|
import com.sun.tools.jdeps.Graph;
|
|
import org.testng.annotations.DataProvider;
|
|
import org.testng.annotations.BeforeTest;
|
|
import org.testng.annotations.Test;
|
|
|
|
import static org.testng.Assert.assertTrue;
|
|
|
|
public class TransitiveDeps {
|
|
private static final String TEST_SRC = System.getProperty("test.src");
|
|
|
|
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
|
private static final Path MODS_DIR = Paths.get("mods");
|
|
private static final Path LIBS_DIR = Paths.get("libs");
|
|
|
|
// the names of the modules in this test
|
|
private static String[] modules = new String[] {"unsafe", "mVI", "mVII"};
|
|
/**
|
|
* Compiles all modules used by the test
|
|
*/
|
|
@BeforeTest
|
|
public void compileAll() throws Exception {
|
|
CompilerUtils.cleanDir(MODS_DIR);
|
|
CompilerUtils.cleanDir(LIBS_DIR);
|
|
|
|
for (String mn : modules) {
|
|
// compile a module
|
|
assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn));
|
|
|
|
// create JAR files with no module-info.class
|
|
Path root = MODS_DIR.resolve(mn);
|
|
try (Stream<Path> stream = Files.walk(root, Integer.MAX_VALUE)) {
|
|
Stream<Path> entries = stream.filter(f -> {
|
|
String fn = f.getFileName().toString();
|
|
return fn.endsWith(".class") && !fn.equals("module-info.class");
|
|
});
|
|
JdepsUtil.createJar(LIBS_DIR.resolve(mn + ".jar"), root, entries);
|
|
}
|
|
}
|
|
}
|
|
|
|
@DataProvider(name = "modules")
|
|
public Object[][] expected1() {
|
|
return new Object[][]{
|
|
{ "mVII",
|
|
List.of(new ModuleMetaData("mVII")
|
|
.requires("mVI")
|
|
.requires("unsafe")
|
|
.reference("p7.Main", "java.lang.Object", "java.base")
|
|
.reference("p7.Main", "java.lang.String", "java.base")
|
|
.reference("p7.Main", "org.safe.Lib", "unsafe")
|
|
.reference("p7.Main", "p6.safe.Lib", "mVI"),
|
|
new ModuleMetaData("mVI")
|
|
.requires("unsafe")
|
|
.reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base")
|
|
.reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe")
|
|
.reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.System", "java.base")
|
|
.reference("p6.safe.Lib", "org.safe.Lib", "unsafe"),
|
|
new ModuleMetaData("unsafe")
|
|
.requires("jdk.unsupported")
|
|
.reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.System", "java.base")
|
|
.reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base")
|
|
.jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base")
|
|
)
|
|
},
|
|
};
|
|
}
|
|
|
|
@Test(dataProvider = "modules")
|
|
public void testModulePath(String name, List<ModuleMetaData> data) throws IOException {
|
|
Set<String> roots = Set.of("mVI", "unsafe");
|
|
|
|
String cmd1 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", MODS_DIR,
|
|
roots.stream().collect(Collectors.joining(",")), name);
|
|
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
|
|
jdeps.verbose("-verbose:class")
|
|
.appModulePath(MODS_DIR.toString())
|
|
.addmods(roots)
|
|
.addmods(Set.of(name));
|
|
|
|
runJdeps(jdeps, data);
|
|
}
|
|
// run automatic modules
|
|
roots = Set.of("ALL-MODULE-PATH", "jdk.unsupported");
|
|
|
|
String cmd2 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", LIBS_DIR,
|
|
roots.stream().collect(Collectors.joining(",")), name);
|
|
|
|
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) {
|
|
jdeps.verbose("-verbose:class")
|
|
.appModulePath(LIBS_DIR.toString())
|
|
.addmods(roots)
|
|
.addmods(Set.of(name));
|
|
|
|
runJdeps(jdeps, data);
|
|
}
|
|
}
|
|
|
|
@DataProvider(name = "jars")
|
|
public Object[][] expected2() {
|
|
return new Object[][]{
|
|
{ "mVII", List.of(new ModuleMetaData("mVII.jar")
|
|
.requires("mVI.jar")
|
|
.requires("unsafe.jar")
|
|
.reference("p7.Main", "java.lang.Object", "java.base")
|
|
.reference("p7.Main", "java.lang.String", "java.base")
|
|
.reference("p7.Main", "org.safe.Lib", "unsafe.jar")
|
|
.reference("p7.Main", "p6.safe.Lib", "mVI.jar"))
|
|
},
|
|
};
|
|
}
|
|
|
|
@Test(dataProvider = "jars")
|
|
public void testClassPath(String name, List<ModuleMetaData> data) throws IOException {
|
|
String cpath = Arrays.stream(modules)
|
|
.filter(mn -> !mn.equals(name))
|
|
.map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
|
|
.collect(Collectors.joining(File.pathSeparator));
|
|
|
|
Path jarfile = LIBS_DIR.resolve(name + ".jar");
|
|
|
|
String cmd = String.format("jdeps -classpath %s %s%n", cpath, jarfile);
|
|
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
|
|
jdeps.verbose("-verbose:class")
|
|
.addClassPath(cpath)
|
|
.addRoot(jarfile);
|
|
|
|
runJdeps(jdeps, data);
|
|
}
|
|
}
|
|
|
|
@DataProvider(name = "compileTimeView")
|
|
public Object[][] expected3() {
|
|
return new Object[][] {
|
|
{"mVII",
|
|
List.of(new ModuleMetaData("mVII.jar")
|
|
.requires("mVI.jar")
|
|
.requires("unsafe.jar")
|
|
.reference("p7.Main", "java.lang.Object", "java.base")
|
|
.reference("p7.Main", "java.lang.String", "java.base")
|
|
.reference("p7.Main", "org.safe.Lib", "unsafe.jar")
|
|
.reference("p7.Main", "p6.safe.Lib", "mVI.jar"),
|
|
new ModuleMetaData("mVI.jar")
|
|
.requires("unsafe.jar")
|
|
.reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base")
|
|
.reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe.jar")
|
|
.reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.System", "java.base")
|
|
.reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"),
|
|
new ModuleMetaData("unsafe.jar")
|
|
.requires("jdk.unsupported")
|
|
.reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.System", "java.base")
|
|
.reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base")
|
|
.jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base")
|
|
)
|
|
},
|
|
};
|
|
}
|
|
|
|
@Test(dataProvider = "compileTimeView")
|
|
public void compileTimeView(String name, List<ModuleMetaData> data) throws IOException {
|
|
String cpath = Arrays.stream(modules)
|
|
.filter(mn -> !mn.equals(name))
|
|
.map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
|
|
.collect(Collectors.joining(File.pathSeparator));
|
|
|
|
Path jarfile = LIBS_DIR.resolve(name + ".jar");
|
|
|
|
String cmd = String.format("jdeps -ct -classpath %s %s%n", cpath, jarfile);
|
|
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
|
|
jdeps.verbose("-verbose:class")
|
|
.addClassPath(cpath)
|
|
.addRoot(jarfile);
|
|
|
|
runJdeps(jdeps, data, true, 0 /* -recursive */);
|
|
}
|
|
}
|
|
|
|
@DataProvider(name = "recursiveDeps")
|
|
public Object[][] expected4() {
|
|
return new Object[][] {
|
|
{"mVII",
|
|
List.of(new ModuleMetaData("mVII.jar")
|
|
.requires("mVI.jar")
|
|
.requires("unsafe.jar")
|
|
.reference("p7.Main", "java.lang.Object", "java.base")
|
|
.reference("p7.Main", "java.lang.String", "java.base")
|
|
.reference("p7.Main", "org.safe.Lib", "unsafe.jar")
|
|
.reference("p7.Main", "p6.safe.Lib", "mVI.jar"),
|
|
new ModuleMetaData("mVI.jar")
|
|
.requires("unsafe.jar")
|
|
.reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("p6.safe.Lib", "java.lang.System", "java.base")
|
|
.reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"),
|
|
new ModuleMetaData("unsafe.jar")
|
|
.requires("jdk.unsupported")
|
|
.reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.io.PrintStream", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Class", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.Object", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.String", "java.base")
|
|
.reference("org.safe.Lib", "java.lang.System", "java.base")
|
|
)
|
|
},
|
|
};
|
|
}
|
|
@Test(dataProvider = "recursiveDeps")
|
|
public void recursiveDeps(String name, List<ModuleMetaData> data) throws IOException {
|
|
String cpath = Arrays.stream(modules)
|
|
.filter(mn -> !mn.equals(name))
|
|
.map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
|
|
.collect(Collectors.joining(File.pathSeparator));
|
|
|
|
Path jarfile = LIBS_DIR.resolve(name + ".jar");
|
|
|
|
String cmd = String.format("jdeps -R -classpath %s %s%n", cpath, jarfile);
|
|
try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
|
|
jdeps.verbose("-verbose:class").filter("-filter:archive")
|
|
.addClassPath(cpath)
|
|
.addRoot(jarfile);
|
|
|
|
runJdeps(jdeps, data, true, 0 /* -recursive */);
|
|
}
|
|
}
|
|
|
|
private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data)
|
|
throws IOException
|
|
{
|
|
runJdeps(jdeps, data, false, 1 /* depth */);
|
|
}
|
|
|
|
private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data,
|
|
boolean compileTimeView, int depth)
|
|
throws IOException
|
|
{
|
|
// run the analyzer
|
|
DepsAnalyzer analyzer = jdeps.getDepsAnalyzer();
|
|
assertTrue(analyzer.run(compileTimeView, depth));
|
|
jdeps.dumpOutput(System.err);
|
|
|
|
// analyze result
|
|
Graph<DepsAnalyzer.Node> g1 = analyzer.moduleGraph();
|
|
Map<String, ModuleMetaData> dataMap = data.stream()
|
|
.collect(Collectors.toMap(ModuleMetaData::name, Function.identity()));
|
|
|
|
// the returned graph contains all nodes such as java.base and jdk.unsupported
|
|
g1.nodes().stream()
|
|
.filter(u -> dataMap.containsKey(u.name))
|
|
.forEach(u -> {
|
|
ModuleMetaData md = dataMap.get(u.name);
|
|
md.checkRequires(u.name, g1.adjacentNodes(u));
|
|
});
|
|
|
|
Graph<DepsAnalyzer.Node> g2 = analyzer.dependenceGraph();
|
|
|
|
g2.nodes().stream()
|
|
.filter(u -> dataMap.containsKey(u.name))
|
|
.forEach(u -> {
|
|
ModuleMetaData md = dataMap.get(u.name);
|
|
md.checkDependences(u.name, g2.adjacentNodes(u));
|
|
});
|
|
}
|
|
}
|