TransitiveDeps.java revision 3792:d516975e8110
1351278Sdim/* 2351278Sdim * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3351278Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4351278Sdim * 5351278Sdim * This code is free software; you can redistribute it and/or modify it 6351278Sdim * under the terms of the GNU General Public License version 2 only, as 7351278Sdim * published by the Free Software Foundation. 8351278Sdim * 9351278Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 10351278Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11351278Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12351278Sdim * version 2 for more details (a copy is included in the LICENSE file that 13351278Sdim * accompanied this code). 14360784Sdim * 15360784Sdim * You should have received a copy of the GNU General Public License version 16351278Sdim * 2 along with this work; if not, write to the Free Software Foundation, 17351278Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18351278Sdim * 19351278Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20351278Sdim * or visit www.oracle.com if you need additional information or have any 21351278Sdim * questions. 22360784Sdim */ 23351278Sdim 24351278Sdim/* 25351278Sdim * @test 26351278Sdim * @summary Tests jdeps -m and -mp options on named modules and unnamed modules 27351278Sdim * @library ../lib 28351278Sdim * @build CompilerUtils JdepsUtil 29351278Sdim * @modules jdk.jdeps/com.sun.tools.jdeps 30351278Sdim * @run testng TransitiveDeps 31351278Sdim */ 32351278Sdim 33360784Sdimimport java.io.File; 34351278Sdimimport java.io.IOException; 35351278Sdim 36351278Sdimimport java.nio.file.Files; 37351278Sdimimport java.nio.file.Path; 38351278Sdimimport java.nio.file.Paths; 39351278Sdimimport java.util.*; 40351278Sdimimport java.util.function.Function; 41351278Sdimimport java.util.stream.Collectors; 42351278Sdimimport java.util.stream.Stream; 43351278Sdim 44351278Sdim 45351278Sdimimport com.sun.tools.jdeps.DepsAnalyzer; 46351278Sdimimport com.sun.tools.jdeps.Graph; 47351278Sdimimport org.testng.annotations.DataProvider; 48351278Sdimimport org.testng.annotations.BeforeTest; 49351278Sdimimport org.testng.annotations.Test; 50351278Sdim 51351278Sdimimport static org.testng.Assert.assertTrue; 52351278Sdim 53351278Sdimpublic class TransitiveDeps { 54351278Sdim private static final String TEST_SRC = System.getProperty("test.src"); 55351278Sdim 56360784Sdim private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 57360784Sdim private static final Path MODS_DIR = Paths.get("mods"); 58360784Sdim private static final Path LIBS_DIR = Paths.get("libs"); 59360784Sdim 60360784Sdim // the names of the modules in this test 61360784Sdim private static String[] modules = new String[] {"unsafe", "mVI", "mVII"}; 62360784Sdim /** 63360784Sdim * Compiles all modules used by the test 64360784Sdim */ 65360784Sdim @BeforeTest 66360784Sdim public void compileAll() throws Exception { 67360784Sdim CompilerUtils.cleanDir(MODS_DIR); 68360784Sdim CompilerUtils.cleanDir(LIBS_DIR); 69351278Sdim 70351278Sdim for (String mn : modules) { 71351278Sdim // compile a module 72351278Sdim assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)); 73360784Sdim 74360784Sdim // create JAR files with no module-info.class 75360784Sdim Path root = MODS_DIR.resolve(mn); 76360784Sdim try (Stream<Path> stream = Files.walk(root, Integer.MAX_VALUE)) { 77351278Sdim Stream<Path> entries = stream.filter(f -> { 78351278Sdim String fn = f.getFileName().toString(); 79351278Sdim return fn.endsWith(".class") && !fn.equals("module-info.class"); 80351278Sdim }); 81351278Sdim JdepsUtil.createJar(LIBS_DIR.resolve(mn + ".jar"), root, entries); 82351278Sdim } 83351278Sdim } 84351278Sdim } 85351278Sdim 86351278Sdim @DataProvider(name = "modules") 87351278Sdim public Object[][] expected1() { 88360784Sdim return new Object[][]{ 89360784Sdim { "mVII", 90360784Sdim List.of(new ModuleMetaData("mVII") 91360784Sdim .requires("mVI") 92360784Sdim .requires("unsafe") 93360784Sdim .reference("p7.Main", "java.lang.Object", "java.base") 94360784Sdim .reference("p7.Main", "java.lang.String", "java.base") 95360784Sdim .reference("p7.Main", "org.safe.Lib", "unsafe") 96360784Sdim .reference("p7.Main", "p6.safe.Lib", "mVI"), 97360784Sdim new ModuleMetaData("mVI") 98360784Sdim .requires("unsafe") 99360784Sdim .reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base") 100360784Sdim .reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe") 101360784Sdim .reference("p6.safe.Lib", "java.io.PrintStream", "java.base") 102360784Sdim .reference("p6.safe.Lib", "java.lang.Class", "java.base") 103360784Sdim .reference("p6.safe.Lib", "java.lang.Object", "java.base") 104360784Sdim .reference("p6.safe.Lib", "java.lang.String", "java.base") 105360784Sdim .reference("p6.safe.Lib", "java.lang.System", "java.base") 106360784Sdim .reference("p6.safe.Lib", "org.safe.Lib", "unsafe"), 107360784Sdim new ModuleMetaData("unsafe") 108360784Sdim .requires("jdk.unsupported") 109360784Sdim .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base") 110360784Sdim .reference("org.safe.Lib", "java.io.PrintStream", "java.base") 111360784Sdim .reference("org.safe.Lib", "java.lang.Class", "java.base") 112360784Sdim .reference("org.safe.Lib", "java.lang.Object", "java.base") 113360784Sdim .reference("org.safe.Lib", "java.lang.String", "java.base") 114360784Sdim .reference("org.safe.Lib", "java.lang.System", "java.base") 115360784Sdim .reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base") 116360784Sdim .jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base") 117360784Sdim ) 118360784Sdim }, 119363496Sdim }; 120360784Sdim } 121360784Sdim 122360784Sdim @Test(dataProvider = "modules") 123360784Sdim public void testModulePath(String name, List<ModuleMetaData> data) throws IOException { 124363496Sdim Set<String> roots = Set.of("mVI", "unsafe"); 125363496Sdim 126363496Sdim String cmd1 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", MODS_DIR, 127363496Sdim roots.stream().collect(Collectors.joining(",")), name); 128363496Sdim try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { 129363496Sdim jdeps.verbose("-verbose:class") 130363496Sdim .appModulePath(MODS_DIR.toString()) 131363496Sdim .addmods(roots) 132363496Sdim .addmods(Set.of(name)); 133363496Sdim 134363496Sdim runJdeps(jdeps, data); 135360784Sdim } 136360784Sdim // run automatic modules 137360784Sdim roots = Set.of("ALL-MODULE-PATH", "jdk.unsupported"); 138360784Sdim 139360784Sdim String cmd2 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", LIBS_DIR, 140360784Sdim roots.stream().collect(Collectors.joining(",")), name); 141360784Sdim 142360784Sdim try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) { 143360784Sdim jdeps.verbose("-verbose:class") 144360784Sdim .appModulePath(LIBS_DIR.toString()) 145360784Sdim .addmods(roots) 146360784Sdim .addmods(Set.of(name)); 147360784Sdim 148360784Sdim runJdeps(jdeps, data); 149360784Sdim } 150360784Sdim } 151360784Sdim 152360784Sdim @DataProvider(name = "jars") 153360784Sdim public Object[][] expected2() { 154360784Sdim return new Object[][]{ 155360784Sdim { "mVII", List.of(new ModuleMetaData("mVII.jar") 156360784Sdim .requires("mVI.jar") 157360784Sdim .requires("unsafe.jar") 158360784Sdim .reference("p7.Main", "java.lang.Object", "java.base") 159360784Sdim .reference("p7.Main", "java.lang.String", "java.base") 160360784Sdim .reference("p7.Main", "org.safe.Lib", "unsafe.jar") 161360784Sdim .reference("p7.Main", "p6.safe.Lib", "mVI.jar")) 162360784Sdim }, 163360784Sdim }; 164360784Sdim } 165360784Sdim 166360784Sdim @Test(dataProvider = "jars") 167360784Sdim public void testClassPath(String name, List<ModuleMetaData> data) throws IOException { 168360784Sdim String cpath = Arrays.stream(modules) 169360784Sdim .filter(mn -> !mn.equals(name)) 170360784Sdim .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString()) 171360784Sdim .collect(Collectors.joining(File.pathSeparator)); 172360784Sdim 173360784Sdim Path jarfile = LIBS_DIR.resolve(name + ".jar"); 174360784Sdim 175360784Sdim String cmd = String.format("jdeps -classpath %s %s%n", cpath, jarfile); 176360784Sdim try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { 177360784Sdim jdeps.verbose("-verbose:class") 178360784Sdim .addClassPath(cpath) 179360784Sdim .addRoot(jarfile); 180360784Sdim 181360784Sdim runJdeps(jdeps, data); 182360784Sdim } 183360784Sdim } 184360784Sdim 185360784Sdim @DataProvider(name = "compileTimeView") 186360784Sdim public Object[][] expected3() { 187360784Sdim return new Object[][] { 188360784Sdim {"mVII", 189360784Sdim List.of(new ModuleMetaData("mVII.jar") 190360784Sdim .requires("mVI.jar") 191360784Sdim .requires("unsafe.jar") 192360784Sdim .reference("p7.Main", "java.lang.Object", "java.base") 193360784Sdim .reference("p7.Main", "java.lang.String", "java.base") 194360784Sdim .reference("p7.Main", "org.safe.Lib", "unsafe.jar") 195360784Sdim .reference("p7.Main", "p6.safe.Lib", "mVI.jar"), 196360784Sdim new ModuleMetaData("mVI.jar") 197360784Sdim .requires("unsafe.jar") 198360784Sdim .reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base") 199360784Sdim .reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe.jar") 200360784Sdim .reference("p6.safe.Lib", "java.io.PrintStream", "java.base") 201360784Sdim .reference("p6.safe.Lib", "java.lang.Class", "java.base") 202360784Sdim .reference("p6.safe.Lib", "java.lang.Object", "java.base") 203360784Sdim .reference("p6.safe.Lib", "java.lang.String", "java.base") 204360784Sdim .reference("p6.safe.Lib", "java.lang.System", "java.base") 205360784Sdim .reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"), 206360784Sdim new ModuleMetaData("unsafe.jar") 207360784Sdim .requires("jdk.unsupported") 208360784Sdim .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base") 209360784Sdim .reference("org.safe.Lib", "java.io.PrintStream", "java.base") 210360784Sdim .reference("org.safe.Lib", "java.lang.Class", "java.base") 211360784Sdim .reference("org.safe.Lib", "java.lang.Object", "java.base") 212360784Sdim .reference("org.safe.Lib", "java.lang.String", "java.base") 213360784Sdim .reference("org.safe.Lib", "java.lang.System", "java.base") 214360784Sdim .reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base") 215360784Sdim .jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base") 216360784Sdim ) 217360784Sdim }, 218360784Sdim }; 219360784Sdim } 220360784Sdim 221360784Sdim @Test(dataProvider = "compileTimeView") 222360784Sdim public void compileTimeView(String name, List<ModuleMetaData> data) throws IOException { 223360784Sdim String cpath = Arrays.stream(modules) 224360784Sdim .filter(mn -> !mn.equals(name)) 225360784Sdim .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString()) 226360784Sdim .collect(Collectors.joining(File.pathSeparator)); 227360784Sdim 228360784Sdim Path jarfile = LIBS_DIR.resolve(name + ".jar"); 229360784Sdim 230360784Sdim String cmd = String.format("jdeps -ct -classpath %s %s%n", cpath, jarfile); 231360784Sdim try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { 232360784Sdim jdeps.verbose("-verbose:class") 233360784Sdim .addClassPath(cpath) 234360784Sdim .addRoot(jarfile); 235360784Sdim 236360784Sdim runJdeps(jdeps, data, true, 0 /* -recursive */); 237360784Sdim } 238360784Sdim } 239351278Sdim 240351278Sdim @DataProvider(name = "recursiveDeps") 241351278Sdim public Object[][] expected4() { 242351278Sdim return new Object[][] { 243351278Sdim {"mVII", 244351278Sdim List.of(new ModuleMetaData("mVII.jar") 245351278Sdim .requires("mVI.jar") 246351278Sdim .requires("unsafe.jar") 247351278Sdim .reference("p7.Main", "java.lang.Object", "java.base") 248351278Sdim .reference("p7.Main", "java.lang.String", "java.base") 249351278Sdim .reference("p7.Main", "org.safe.Lib", "unsafe.jar") 250351278Sdim .reference("p7.Main", "p6.safe.Lib", "mVI.jar"), 251351278Sdim new ModuleMetaData("mVI.jar") 252351278Sdim .requires("unsafe.jar") 253351278Sdim .reference("p6.safe.Lib", "java.io.PrintStream", "java.base") 254351278Sdim .reference("p6.safe.Lib", "java.lang.Class", "java.base") 255351278Sdim .reference("p6.safe.Lib", "java.lang.Object", "java.base") 256351278Sdim .reference("p6.safe.Lib", "java.lang.String", "java.base") 257351278Sdim .reference("p6.safe.Lib", "java.lang.System", "java.base") 258351278Sdim .reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"), 259351278Sdim new ModuleMetaData("unsafe.jar") 260351278Sdim .requires("jdk.unsupported") 261351278Sdim .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base") 262351278Sdim .reference("org.safe.Lib", "java.io.PrintStream", "java.base") 263351278Sdim .reference("org.safe.Lib", "java.lang.Class", "java.base") 264351278Sdim .reference("org.safe.Lib", "java.lang.Object", "java.base") 265360784Sdim .reference("org.safe.Lib", "java.lang.String", "java.base") 266360784Sdim .reference("org.safe.Lib", "java.lang.System", "java.base") 267351278Sdim ) 268351278Sdim }, 269351278Sdim }; 270351278Sdim } 271351278Sdim @Test(dataProvider = "recursiveDeps") 272351278Sdim public void recursiveDeps(String name, List<ModuleMetaData> data) throws IOException { 273360784Sdim String cpath = Arrays.stream(modules) 274351278Sdim .filter(mn -> !mn.equals(name)) 275351278Sdim .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString()) 276351278Sdim .collect(Collectors.joining(File.pathSeparator)); 277360784Sdim 278351278Sdim Path jarfile = LIBS_DIR.resolve(name + ".jar"); 279351278Sdim 280351278Sdim String cmd = String.format("jdeps -R -classpath %s %s%n", cpath, jarfile); 281351278Sdim try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { 282351278Sdim jdeps.verbose("-verbose:class").filter("-filter:archive") 283360784Sdim .addClassPath(cpath) 284351278Sdim .addRoot(jarfile); 285351278Sdim 286351278Sdim runJdeps(jdeps, data, true, 0 /* -recursive */); 287351278Sdim } 288351278Sdim } 289351278Sdim 290351278Sdim private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data) 291351278Sdim throws IOException 292351278Sdim { 293360784Sdim runJdeps(jdeps, data, false, 1 /* depth */); 294351278Sdim } 295351278Sdim 296351278Sdim private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data, 297351278Sdim boolean compileTimeView, int depth) 298351278Sdim throws IOException 299351278Sdim { 300351278Sdim // run the analyzer 301351278Sdim DepsAnalyzer analyzer = jdeps.getDepsAnalyzer(); 302351278Sdim assertTrue(analyzer.run(compileTimeView, depth)); 303351278Sdim jdeps.dumpOutput(System.err); 304351278Sdim 305351278Sdim // analyze result 306351278Sdim Graph<DepsAnalyzer.Node> g1 = analyzer.moduleGraph(); 307351278Sdim Map<String, ModuleMetaData> dataMap = data.stream() 308351278Sdim .collect(Collectors.toMap(ModuleMetaData::name, Function.identity())); 309351278Sdim 310351278Sdim // the returned graph contains all nodes such as java.base and jdk.unsupported 311351278Sdim g1.nodes().stream() 312 .filter(u -> dataMap.containsKey(u.name)) 313 .forEach(u -> { 314 ModuleMetaData md = dataMap.get(u.name); 315 md.checkRequires(u.name, g1.adjacentNodes(u)); 316 }); 317 318 Graph<DepsAnalyzer.Node> g2 = analyzer.dependenceGraph(); 319 320 g2.nodes().stream() 321 .filter(u -> dataMap.containsKey(u.name)) 322 .forEach(u -> { 323 ModuleMetaData md = dataMap.get(u.name); 324 md.checkDependences(u.name, g2.adjacentNodes(u)); 325 }); 326 } 327} 328