1 /* 2 * Copyright (c) 2016, 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 * @summary Tests split packages 27 * @library ../lib 28 * @build CompilerUtils JdepsUtil 29 * @modules jdk.jdeps/com.sun.tools.jdeps 30 * @run testng InverseDeps 31 */ 32 33 import java.io.File; 34 import java.nio.file.Files; 35 import java.nio.file.Path; 36 import java.nio.file.Paths; 37 import java.util.Arrays; 38 import java.util.LinkedHashSet; 39 import java.util.List; 40 import java.util.Set; 41 import java.util.stream.Collectors; 42 import java.util.stream.Stream; 43 44 import com.sun.tools.jdeps.Archive; 45 import com.sun.tools.jdeps.InverseDepsAnalyzer; 46 import org.testng.annotations.BeforeTest; 47 import org.testng.annotations.DataProvider; 48 import org.testng.annotations.Test; 49 50 import static org.testng.Assert.assertTrue; 51 import static org.testng.Assert.assertFalse; 52 import static org.testng.Assert.assertEquals; 53 54 55 public class InverseDeps { 56 private static final String TEST_SRC = System.getProperty("test.src"); 57 private static final String TEST_CLASSES = System.getProperty("test.classes"); 58 59 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 60 private static final Path MODS_DIR = Paths.get("mods"); 61 private static final Path LIBS_DIR = Paths.get("libs"); 62 63 private static final Set<String> modules = new LinkedHashSet( 64 List.of("unsafe", "m4", "m5", "m6", "m7") 65 ); 66 67 /** 68 * Compiles classes used by the test 69 */ 70 @BeforeTest 71 public void compileAll() throws Exception { 72 CompilerUtils.cleanDir(MODS_DIR); 73 74 for (String mn : modules) { 75 // compile a module 76 assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)); 77 78 // create JAR files with no module-info.class 79 Path root = MODS_DIR.resolve(mn); 80 81 try (Stream<Path> stream = Files.walk(root, Integer.MAX_VALUE)) { 82 Stream<Path> entries = stream.filter(f -> { 83 String fn = f.getFileName().toString(); 84 return fn.endsWith(".class") && !fn.equals("module-info.class"); 85 }); 86 JdepsUtil.createJar(LIBS_DIR.resolve(mn + ".jar"), root, entries); 87 } 88 } 89 } 90 91 @DataProvider(name = "testrequires") 92 public Object[][] expected1() { 93 return new Object[][] { 94 // -requires and result 95 { "java.sql", new String[][] { 96 new String[] { "java.sql", "m5" }, 97 } 98 }, 99 { "java.compiler", new String[][] { 100 new String[] { "java.compiler", "m5" }, 101 new String[] { "java.compiler", "m4", "m5" }, 102 } 103 }, 104 { "java.logging", new String[][]{ 105 new String[] {"java.logging", "m5"}, 106 new String[] {"java.logging", "m4", "m5"}, 107 new String[] {"java.logging", "java.sql", "m5"}, 108 } 109 }, 110 { "jdk.unsupported", new String[][] { 111 new String[] {"jdk.unsupported", "unsafe", "m6", "m7"}, 112 new String[] {"jdk.unsupported", "unsafe", "m7"} 113 } 114 }, 115 }; 116 } 117 118 @Test(dataProvider = "testrequires") 119 public void testrequires(String name, String[][] expected) throws Exception { 120 String cmd1 = String.format("jdeps -inverse -modulepath %s -requires %s -addmods %s%n", 121 MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); 122 123 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { 124 jdeps.appModulePath(MODS_DIR.toString()) 125 .addmods(modules) 126 .requires(Set.of(name)); 127 128 runJdeps(jdeps, expected); 129 } 130 131 String cmd2 = String.format("jdeps -inverse -modulepath %s -requires %s" + 132 " -addmods ALL-MODULE-PATH%n", LIBS_DIR, name); 133 134 // automatic module 135 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) { 136 jdeps.appModulePath(MODS_DIR.toString()) 137 .addmods(Set.of("ALL-MODULE-PATH")) 138 .requires(Set.of(name)); 139 140 runJdeps(jdeps, expected); 141 } 142 } 143 144 @DataProvider(name = "testpackage") 145 public Object[][] expected2() { 146 return new Object[][] { 147 // -package and result 148 { "p4", new String[][] { 149 new String[] { "m4", "m5"}, 150 } 151 }, 152 { "javax.tools", new String[][] { 153 new String[] {"java.compiler", "m5"}, 154 new String[] {"java.compiler", "m4", "m5"}, 155 } 156 }, 157 { "sun.misc", new String[][] { 158 new String[] {"jdk.unsupported", "unsafe", "m6", "m7"}, 159 new String[] {"jdk.unsupported", "unsafe", "m7"} 160 } 161 } 162 }; 163 } 164 165 @Test(dataProvider = "testpackage") 166 public void testpackage(String name, String[][] expected) throws Exception { 167 String cmd = String.format("jdeps -inverse -modulepath %s -package %s -addmods %s%n", 168 MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); 169 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { 170 jdeps.appModulePath(MODS_DIR.toString()) 171 .addmods(modules) 172 .matchPackages(Set.of(name)); 173 174 runJdeps(jdeps, expected); 175 } 176 } 177 178 @DataProvider(name = "testregex") 179 public Object[][] expected3() { 180 return new Object[][] { 181 // -regex and result 182 { "org.safe.Lib", new String[][] { 183 new String[] { "unsafe", "m7"}, 184 new String[] { "unsafe", "m6", "m7"}, 185 } 186 }, 187 { "java.util.logging.*|org.safe.Lib", new String[][] { 188 new String[] { "unsafe", "m7"}, 189 new String[] { "unsafe", "m6", "m7"}, 190 new String[] { "java.logging", "m5"}, 191 } 192 } 193 }; 194 } 195 196 @Test(dataProvider = "testregex") 197 public void testregex(String name, String[][] expected) throws Exception { 198 String cmd = String.format("jdeps -inverse -modulepath %s -regex %s -addmods %s%n", 199 MODS_DIR, name, modules.stream().collect(Collectors.joining(","))); 200 201 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) { 202 jdeps.appModulePath(MODS_DIR.toString()) 203 .addmods(modules) 204 .regex(name); 205 206 runJdeps(jdeps, expected); 207 } 208 } 209 210 @DataProvider(name = "classpath") 211 public Object[][] expected4() { 212 return new Object[][] { 213 // -regex and result 214 { "sun.misc.Unsafe", new String[][] { 215 new String[] {"jdk.unsupported", "unsafe.jar", "m6.jar", "m7.jar"}, 216 new String[] {"jdk.unsupported", "unsafe.jar", "m7.jar"} 217 } 218 }, 219 { "org.safe.Lib", new String[][] { 220 new String[] { "unsafe.jar", "m7.jar"}, 221 new String[] { "unsafe.jar", "m6.jar", "m7.jar"}, 222 } 223 }, 224 { "java.util.logging.*|org.safe.Lib", new String[][] { 225 new String[] { "unsafe.jar", "m7.jar"}, 226 new String[] { "unsafe.jar", "m6.jar", "m7.jar"}, 227 new String[] { "java.logging", "m5.jar"}, 228 } 229 } 230 }; 231 } 232 233 @Test(dataProvider = "classpath") 234 public void testClassPath(String name, String[][] expected) throws Exception { 235 // -classpath 236 String cpath = modules.stream() 237 .filter(mn -> !mn.equals("m7")) 238 .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString()) 239 .collect(Collectors.joining(File.pathSeparator)); 240 241 Path jarfile = LIBS_DIR.resolve("m7.jar"); 242 243 String cmd1 = String.format("jdeps -inverse -classpath %s -regex %s %s%n", 244 cpath, name, jarfile); 245 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) { 246 jdeps.verbose("-verbose:class") 247 .addClassPath(cpath) 248 .regex(name).addRoot(jarfile); 249 runJdeps(jdeps, expected); 250 } 251 252 // all JAR files on the command-line arguments 253 Set<Path> paths = modules.stream() 254 .map(mn -> LIBS_DIR.resolve(mn + ".jar")) 255 .collect(Collectors.toSet()); 256 String cmd2 = String.format("jdeps -inverse -regex %s %s%n", name, paths); 257 try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) { 258 jdeps.verbose("-verbose:class").regex(name); 259 paths.forEach(jdeps::addRoot); 260 runJdeps(jdeps, expected); 261 } 262 } 263 264 private void runJdeps(JdepsUtil.Command jdeps, String[][] expected) throws Exception { 265 InverseDepsAnalyzer analyzer = jdeps.getInverseDepsAnalyzer(); 266 267 assertTrue(analyzer.run()); 268 269 // get the inverse transitive dependences 270 List<String[]> paths = analyzer.inverseDependences().stream() 271 .map(deque -> deque.stream() 272 .map(Archive::getName) 273 .collect(Collectors.toList()).toArray(new String[0])) 274 .collect(Collectors.toList()); 275 276 jdeps.dumpOutput(System.err); 277 paths.forEach(path -> System.err.println(Arrays.stream(path) 278 .collect(Collectors.joining(" <- ")))); 279 280 // verify the dependences 281 assertEquals(paths.size(), expected.length); 282 283 for (int i=0; i < paths.size(); i++) { 284 String[] path = paths.get(i); 285 boolean noneMatched = Arrays.stream(expected) 286 .filter(array -> array.length == path.length) 287 .noneMatch(array -> Arrays.equals(array, path)); 288 if (noneMatched) 289 System.err.format("Expected: %s found: %s%n", 290 Arrays.stream(expected) 291 .map(Arrays::toString) 292 .collect(Collectors.joining(", ")), 293 Arrays.toString(path)); 294 295 assertFalse(noneMatched); 296 } 297 } 298 299 }