mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
8156680: jdeps implementation refresh
Reviewed-by: dfuchs
This commit is contained in:
parent
d027cbbffb
commit
bbc75367c7
47 changed files with 4474 additions and 2286 deletions
|
@ -24,30 +24,28 @@
|
|||
/*
|
||||
* @test
|
||||
* @summary Tests jdeps -m and -mp options on named modules and unnamed modules
|
||||
* @library ..
|
||||
* @build CompilerUtils
|
||||
* @library ../lib
|
||||
* @build CompilerUtils JdepsUtil
|
||||
* @modules jdk.jdeps/com.sun.tools.jdeps
|
||||
* @run testng ModuleTest
|
||||
*/
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
|
||||
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.stream.Collectors;
|
||||
|
||||
|
||||
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.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
public class ModuleTest {
|
||||
|
@ -56,6 +54,7 @@ public class ModuleTest {
|
|||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
private static final Path UNNAMED_DIR = Paths.get("unnamed");
|
||||
|
||||
// the names of the modules in this test
|
||||
private static final String UNSUPPORTED = "unsupported";
|
||||
|
@ -66,62 +65,68 @@ public class ModuleTest {
|
|||
@BeforeTest
|
||||
public void compileAll() throws Exception {
|
||||
CompilerUtils.cleanDir(MODS_DIR);
|
||||
CompilerUtils.cleanDir(UNNAMED_DIR);
|
||||
|
||||
assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, UNSUPPORTED,
|
||||
"-XaddExports:java.base/jdk.internal.perf=" + UNSUPPORTED));
|
||||
// m4 is not referenced
|
||||
Arrays.asList("m1", "m2", "m3", "m4")
|
||||
.forEach(mn -> assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)));
|
||||
|
||||
assertTrue(CompilerUtils.compile(SRC_DIR.resolve("m3"), UNNAMED_DIR, "-mp", MODS_DIR.toString()));
|
||||
Files.delete(UNNAMED_DIR.resolve("module-info.class"));
|
||||
}
|
||||
|
||||
@DataProvider(name = "modules")
|
||||
public Object[][] expected() {
|
||||
return new Object[][]{
|
||||
{ "m3", new Data("m3").requiresPublic("java.sql")
|
||||
.requiresPublic("m2")
|
||||
.requires("java.logging")
|
||||
.requiresPublic("m1")
|
||||
.reference("p3", "java.lang", "java.base")
|
||||
.reference("p3", "java.sql", "java.sql")
|
||||
.reference("p3", "java.util.logging", "java.logging")
|
||||
.reference("p3", "p1", "m1")
|
||||
.reference("p3", "p2", "m2")
|
||||
.qualified("p3", "p2.internal", "m2")
|
||||
{ "m3", new ModuleMetaData("m3").requiresPublic("java.sql")
|
||||
.requiresPublic("m2")
|
||||
.requires("java.logging")
|
||||
.requiresPublic("m1")
|
||||
.reference("p3", "java.lang", "java.base")
|
||||
.reference("p3", "java.sql", "java.sql")
|
||||
.reference("p3", "java.util.logging", "java.logging")
|
||||
.reference("p3", "p1", "m1")
|
||||
.reference("p3", "p2", "m2")
|
||||
.qualified("p3", "p2.internal", "m2")
|
||||
},
|
||||
{ "m2", new Data("m2").requiresPublic("m1")
|
||||
.reference("p2", "java.lang", "java.base")
|
||||
.reference("p2", "p1", "m1")
|
||||
.reference("p2.internal", "java.lang", "java.base")
|
||||
.reference("p2.internal", "java.io", "java.base")
|
||||
{ "m2", new ModuleMetaData("m2").requiresPublic("m1")
|
||||
.reference("p2", "java.lang", "java.base")
|
||||
.reference("p2", "p1", "m1")
|
||||
.reference("p2.internal", "java.lang", "java.base")
|
||||
.reference("p2.internal", "java.io", "java.base")
|
||||
},
|
||||
{ "m1", new Data("m1").requires("unsupported")
|
||||
.reference("p1", "java.lang", "java.base")
|
||||
.reference("p1.internal", "java.lang", "java.base")
|
||||
.reference("p1.internal", "p1", "m1")
|
||||
.reference("p1.internal", "q", "unsupported")
|
||||
{ "m1", new ModuleMetaData("m1").requires("unsupported")
|
||||
.reference("p1", "java.lang", "java.base")
|
||||
.reference("p1.internal", "java.lang", "java.base")
|
||||
.reference("p1.internal", "p1", "m1")
|
||||
.reference("p1.internal", "q", "unsupported")
|
||||
},
|
||||
{ "unsupported", new Data("unsupported")
|
||||
.reference("q", "java.lang", "java.base")
|
||||
.jdkInternal("q", "jdk.internal.perf", "(java.base)")
|
||||
{ "unsupported", new ModuleMetaData("unsupported")
|
||||
.reference("q", "java.lang", "java.base")
|
||||
.jdkInternal("q", "jdk.internal.perf", "java.base")
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "modules")
|
||||
public void modularTest(String name, Data data) {
|
||||
// print only the specified module
|
||||
String excludes = Arrays.stream(modules)
|
||||
.filter(mn -> !mn.endsWith(name))
|
||||
.collect(Collectors.joining(","));
|
||||
String[] result = jdeps("-exclude-modules", excludes,
|
||||
"-mp", MODS_DIR.toString(),
|
||||
"-m", name);
|
||||
assertTrue(data.check(result));
|
||||
public void modularTest(String name, ModuleMetaData data) throws IOException {
|
||||
// jdeps -modulepath mods -m <name>
|
||||
runTest(data, MODS_DIR.toString(), Set.of(name));
|
||||
|
||||
// jdeps -modulepath libs/m1.jar:.... -m <name>
|
||||
String mp = Arrays.stream(modules)
|
||||
.filter(mn -> !mn.equals(name))
|
||||
.map(mn -> MODS_DIR.resolve(mn).toString())
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
runTest(data, mp, Collections.emptySet(), MODS_DIR.resolve(name));
|
||||
}
|
||||
|
||||
@DataProvider(name = "unnamed")
|
||||
public Object[][] unnamed() {
|
||||
return new Object[][]{
|
||||
{ "m3", new Data("m3", false)
|
||||
{ "unnamed", new ModuleMetaData("unnamed", false)
|
||||
.depends("java.sql")
|
||||
.depends("java.logging")
|
||||
.depends("m1")
|
||||
|
@ -133,178 +138,43 @@ public class ModuleTest {
|
|||
.reference("p3", "p2", "m2")
|
||||
.internal("p3", "p2.internal", "m2")
|
||||
},
|
||||
{ "unsupported", new Data("unsupported", false)
|
||||
.reference("q", "java.lang", "java.base")
|
||||
.jdkInternal("q", "jdk.internal.perf", "(java.base)")
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "unnamed")
|
||||
public void unnamedTest(String name, Data data) {
|
||||
String[] result = jdeps("-mp", MODS_DIR.toString(), MODS_DIR.resolve(name).toString());
|
||||
assertTrue(data.check(result));
|
||||
public void unnamedTest(String name, ModuleMetaData data) throws IOException {
|
||||
runTest(data, MODS_DIR.toString(), Set.of("m1", "m2"), UNNAMED_DIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs jdeps with the given arguments
|
||||
*/
|
||||
public static String[] jdeps(String... args) {
|
||||
String lineSep = System.getProperty("line.separator");
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
System.err.println("jdeps " + Arrays.toString(args));
|
||||
int rc = com.sun.tools.jdeps.Main.run(args, pw);
|
||||
pw.close();
|
||||
String out = sw.toString();
|
||||
if (!out.isEmpty())
|
||||
System.err.println(out);
|
||||
if (rc != 0)
|
||||
throw new Error("jdeps failed: rc=" + rc);
|
||||
return out.split(lineSep);
|
||||
}
|
||||
private void runTest(ModuleMetaData data, String modulepath,
|
||||
Set<String> roots, Path... paths)
|
||||
throws IOException
|
||||
{
|
||||
// jdeps -modulepath <modulepath> -m root paths
|
||||
|
||||
static class Data {
|
||||
static final String INTERNAL = "(internal)";
|
||||
static final String QUALIFIED = "(qualified)";
|
||||
static final String JDK_INTERNAL = "JDK internal API";
|
||||
JdepsUtil.Command jdeps = JdepsUtil.newCommand(
|
||||
String.format("jdeps -modulepath %s -addmods %s %s%n", MODS_DIR,
|
||||
roots.stream().collect(Collectors.joining(",")), paths)
|
||||
);
|
||||
jdeps.appModulePath(modulepath)
|
||||
.addmods(roots);
|
||||
Arrays.stream(paths).forEach(jdeps::addRoot);
|
||||
|
||||
final String moduleName;
|
||||
final boolean isNamed;
|
||||
final Map<String, ModuleRequires> requires = new LinkedHashMap<>();
|
||||
final Map<String, Dependence> references = new LinkedHashMap<>();
|
||||
Data(String name) {
|
||||
this(name, true);
|
||||
}
|
||||
Data(String name, boolean isNamed) {
|
||||
this.moduleName = name;
|
||||
this.isNamed = isNamed;
|
||||
requires("java.base"); // implicit requires
|
||||
}
|
||||
// run the analyzer
|
||||
DepsAnalyzer analyzer = jdeps.getDepsAnalyzer();
|
||||
assertTrue(analyzer.run());
|
||||
|
||||
Data requires(String name) {
|
||||
requires.put(name, new ModuleRequires(name));
|
||||
return this;
|
||||
}
|
||||
Data requiresPublic(String name) {
|
||||
requires.put(name, new ModuleRequires(name, PUBLIC));
|
||||
return this;
|
||||
}
|
||||
// for unnamed module
|
||||
Data depends(String name) {
|
||||
requires.put(name, new ModuleRequires(name));
|
||||
return this;
|
||||
}
|
||||
Data reference(String origin, String target, String module) {
|
||||
return dependence(origin, target, module, "");
|
||||
}
|
||||
Data internal(String origin, String target, String module) {
|
||||
return dependence(origin, target, module, INTERNAL);
|
||||
}
|
||||
Data qualified(String origin, String target, String module) {
|
||||
return dependence(origin, target, module, QUALIFIED);
|
||||
}
|
||||
Data jdkInternal(String origin, String target, String module) {
|
||||
return dependence(origin, target, module, JDK_INTERNAL);
|
||||
}
|
||||
private Data dependence(String origin, String target, String module, String access) {
|
||||
references.put(key(origin, target), new Dependence(origin, target, module, access));
|
||||
return this;
|
||||
}
|
||||
// analyze result
|
||||
Graph<DepsAnalyzer.Node> g1 = analyzer.moduleGraph();
|
||||
g1.nodes().stream()
|
||||
.filter(u -> u.name.equals(data.moduleName))
|
||||
.forEach(u -> data.checkRequires(u.name, g1.adjacentNodes(u)));
|
||||
|
||||
String key(String origin, String target) {
|
||||
return origin+":"+target;
|
||||
}
|
||||
boolean check(String[] lines) {
|
||||
System.out.format("verifying module %s%s%n", moduleName, isNamed ? "" : " (unnamed module)");
|
||||
for (String l : lines) {
|
||||
String[] tokens = l.trim().split("\\s+");
|
||||
System.out.println(" " + Arrays.stream(tokens).collect(Collectors.joining(" ")));
|
||||
switch (tokens[0]) {
|
||||
case "module":
|
||||
assertEquals(tokens.length, 2);
|
||||
assertEquals(moduleName, tokens[1]);
|
||||
break;
|
||||
case "requires":
|
||||
String name = tokens.length == 2 ? tokens[1] : tokens[2];
|
||||
Modifier modifier = null;
|
||||
if (tokens.length == 3) {
|
||||
assertEquals("public", tokens[1]);
|
||||
modifier = PUBLIC;
|
||||
}
|
||||
checkRequires(name, modifier);
|
||||
break;
|
||||
default:
|
||||
if (tokens.length == 3) {
|
||||
// unnamed module requires
|
||||
assertFalse(isNamed);
|
||||
assertEquals(moduleName, tokens[0]);
|
||||
String mn = tokens[2];
|
||||
checkRequires(mn, null);
|
||||
} else {
|
||||
checkDependence(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Graph<DepsAnalyzer.Node> g2 = analyzer.dependenceGraph();
|
||||
g2.nodes().stream()
|
||||
.filter(u -> u.name.equals(data.moduleName))
|
||||
.forEach(u -> data.checkDependences(u.name, g2.adjacentNodes(u)));
|
||||
|
||||
private void checkRequires(String name, Modifier modifier) {
|
||||
assertTrue(requires.containsKey(name));
|
||||
ModuleRequires req = requires.get(name);
|
||||
assertEquals(req.mod, modifier);
|
||||
}
|
||||
|
||||
private void checkDependence(String[] tokens) {
|
||||
assertTrue(tokens.length >= 4);
|
||||
String origin = tokens[0];
|
||||
String target = tokens[2];
|
||||
String module = tokens[3];
|
||||
String key = key(origin, target);
|
||||
assertTrue(references.containsKey(key));
|
||||
Dependence dep = references.get(key);
|
||||
if (tokens.length == 4) {
|
||||
assertEquals(dep.access, "");
|
||||
} else if (tokens.length == 5) {
|
||||
assertEquals(dep.access, tokens[4]);
|
||||
} else {
|
||||
// JDK internal API
|
||||
module = tokens[6];
|
||||
assertEquals(tokens.length, 7);
|
||||
assertEquals(tokens[3], "JDK");
|
||||
assertEquals(tokens[4], "internal");
|
||||
assertEquals(tokens[5], "API");
|
||||
}
|
||||
assertEquals(dep.module, module);
|
||||
}
|
||||
|
||||
public static class ModuleRequires {
|
||||
final String name;
|
||||
final ModuleDescriptor.Requires.Modifier mod;
|
||||
|
||||
ModuleRequires(String name) {
|
||||
this.name = name;
|
||||
this.mod = null;
|
||||
}
|
||||
|
||||
ModuleRequires(String name, ModuleDescriptor.Requires.Modifier mod) {
|
||||
this.name = name;
|
||||
this.mod = mod;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dependence {
|
||||
final String origin;
|
||||
final String target;
|
||||
final String module;
|
||||
final String access;
|
||||
|
||||
Dependence(String origin, String target, String module, String access) {
|
||||
this.origin = origin;
|
||||
this.target = target;
|
||||
this.module = module;
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
jdeps.dumpOutput(System.err);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue