InverseDeps.java revision 3792:d516975e8110
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
33import java.io.File;
34import java.nio.file.Files;
35import java.nio.file.Path;
36import java.nio.file.Paths;
37import java.util.Arrays;
38import java.util.LinkedHashSet;
39import java.util.List;
40import java.util.Set;
41import java.util.stream.Collectors;
42import java.util.stream.Stream;
43
44import com.sun.tools.jdeps.Archive;
45import com.sun.tools.jdeps.InverseDepsAnalyzer;
46import org.testng.annotations.BeforeTest;
47import org.testng.annotations.DataProvider;
48import org.testng.annotations.Test;
49
50import static org.testng.Assert.assertTrue;
51import static org.testng.Assert.assertFalse;
52import static org.testng.Assert.assertEquals;
53
54
55public 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", "mVI", "mVII")
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            // --require 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", "mVI", "mVII"},
112                    new String[] {"jdk.unsupported", "unsafe", "mVII"}
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 --module-path %s --require %s --add-modules %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 --module-path %s --require %s" +
132            " --add-modules 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", "mVI", "mVII"},
159                        new String[] {"jdk.unsupported", "unsafe", "mVII"}
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 --module-path %s -package %s --add-modules %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", "mVII"},
184                    new String[] { "unsafe", "mVI", "mVII"},
185                }
186            },
187            { "java.util.logging.*|org.safe.Lib", new String[][] {
188                    new String[] { "unsafe", "mVII"},
189                    new String[] { "unsafe", "mVI", "mVII"},
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 --module-path %s -regex %s --add-modules %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", "mVI.jar", "mVII.jar"},
216                    new String[] {"jdk.unsupported", "unsafe.jar", "mVII.jar"}
217                }
218            },
219            { "org.safe.Lib", new String[][] {
220                    new String[] { "unsafe.jar", "mVII.jar"},
221                    new String[] { "unsafe.jar", "mVI.jar", "mVII.jar"},
222                }
223            },
224            { "java.util.logging.*|org.safe.Lib", new String[][] {
225                    new String[] { "unsafe.jar", "mVII.jar"},
226                    new String[] { "unsafe.jar", "mVI.jar", "mVII.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("mVII"))
238            .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
239            .collect(Collectors.joining(File.pathSeparator));
240
241        Path jarfile = LIBS_DIR.resolve("mVII.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}
300