DotFileTest.java revision 2571:10fc81ac75b4
1/*
2 * Copyright (c) 2014, 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 * @bug 8003562
27 * @summary Basic tests for jdeps -dotoutput option
28 * @build Test p.Foo p.Bar javax.activity.NotCompactProfile
29 * @run main DotFileTest
30 */
31
32import java.io.File;
33import java.io.IOException;
34import java.io.PrintWriter;
35import java.io.StringWriter;
36import java.nio.file.DirectoryStream;
37import java.nio.file.Files;
38import java.nio.file.Path;
39import java.nio.file.Paths;
40import java.util.*;
41import java.util.regex.*;
42
43public class DotFileTest {
44    private static boolean symbolFileExist = initProfiles();
45    private static boolean initProfiles() {
46        // check if ct.sym exists; if not use the profiles.properties file
47        Path home = Paths.get(System.getProperty("java.home"));
48        if (home.endsWith("jre")) {
49            home = home.getParent();
50        }
51        Path ctsym = home.resolve("lib").resolve("ct.sym");
52        boolean symbolExists = ctsym.toFile().exists();
53        if (!symbolExists) {
54            Path testSrcProfiles =
55                Paths.get(System.getProperty("test.src", "."), "profiles.properties");
56            if (!testSrcProfiles.toFile().exists())
57                throw new Error(testSrcProfiles + " does not exist");
58            System.out.format("%s doesn't exist.%nUse %s to initialize profiles info%n",
59                ctsym, testSrcProfiles);
60            System.setProperty("jdeps.profiles", testSrcProfiles.toString());
61        }
62        return symbolExists;
63    }
64
65    public static void main(String... args) throws Exception {
66        int errors = 0;
67        errors += new DotFileTest().run();
68        if (errors > 0)
69            throw new Exception(errors + " errors found");
70    }
71
72    final Path dir;
73    final Path dotoutput;
74    DotFileTest() {
75        this.dir = Paths.get(System.getProperty("test.classes", "."));
76        this.dotoutput = dir.resolve("dots");
77    }
78
79    int run() throws IOException {
80        File testDir = dir.toFile();
81        // test a .class file
82        test(new File(testDir, "Test.class"),
83             new String[] {"java.lang", "p"},
84             new String[] {"compact1", "not found"});
85        // test a directory
86        // also test non-SE javax.activity class dependency
87        test(new File(testDir, "p"),
88             new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto"},
89             new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1"},
90             new String[] {"-classpath", testDir.getPath()});
91        // test class-level dependency output
92        test(new File(testDir, "Test.class"),
93             new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
94             new String[] {"compact1", "compact1", "not found", "not found"},
95             new String[] {"-verbose:class"});
96        // test -filter:none option
97        test(new File(testDir, "p"),
98             new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto", "p"},
99             new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1", "p"},
100             new String[] {"-classpath", testDir.getPath(), "-verbose:package", "-filter:none"});
101        // test -filter:archive option
102        test(new File(testDir, "p"),
103             new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto"},
104             new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1"},
105             new String[] {"-classpath", testDir.getPath(), "-verbose:package", "-filter:archive"});
106        // test -p option
107        test(new File(testDir, "Test.class"),
108             new String[] {"p.Foo", "p.Bar"},
109             new String[] {"not found", "not found"},
110             new String[] {"-verbose:class", "-p", "p"});
111        // test -e option
112        test(new File(testDir, "Test.class"),
113             new String[] {"p.Foo", "p.Bar"},
114             new String[] {"not found", "not found"},
115             new String[] {"-verbose:class", "-e", "p\\..*"});
116        test(new File(testDir, "Test.class"),
117             new String[] {"java.lang"},
118             new String[] {"compact1"},
119             new String[] {"-verbose:package", "-e", "java\\.lang\\..*"});
120        // test -classpath options
121        test(new File(testDir, "Test.class"),
122             new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
123             new String[] {"compact1", "compact1", testDir.getName(), testDir.getName()},
124             new String[] {"-v", "-classpath", testDir.getPath()});
125
126        testSummary(new File(testDir, "Test.class"),
127             new String[] {"java.base", testDir.getName()},
128             new String[] {"compact1", ""},
129             new String[] {"-classpath", testDir.getPath()});
130        testSummary(new File(testDir, "Test.class"),
131             new String[] {"java.lang", "p"},
132             new String[] {"compact1", testDir.getName()},
133             new String[] {"-v", "-classpath", testDir.getPath()});
134        return errors;
135    }
136
137    void test(File file, String[] expect, String[] profiles) throws IOException {
138        test(file, expect, profiles, new String[0]);
139    }
140
141    void test(File file, String[] expect, String[] profiles, String[] options)
142        throws IOException
143    {
144        Path dotfile = dotoutput.resolve(file.toPath().getFileName().toString() + ".dot");
145
146        List<String> args = new ArrayList<>(Arrays.asList(options));
147        args.add("-dotoutput");
148        args.add(dotoutput.toString());
149        if (file != null) {
150            args.add(file.getPath());
151        }
152
153        Map<String,String> result = jdeps(args, dotfile);
154        checkResult("dependencies", expect, result.keySet());
155
156        // with -P option
157        List<String> argsWithDashP = new ArrayList<>();
158        argsWithDashP.add("-dotoutput");
159        argsWithDashP.add(dotoutput.toString());
160        argsWithDashP.add("-P");
161        argsWithDashP.addAll(args);
162
163        result = jdeps(argsWithDashP, dotfile);
164        checkResult("profiles", expect, profiles, result);
165    }
166
167    void testSummary(File file, String[] expect, String[] profiles, String[] options)
168        throws IOException
169    {
170        Path dotfile = dotoutput.resolve("summary.dot");
171
172        List<String> args = new ArrayList<>(Arrays.asList(options));
173        args.add("-dotoutput");
174        args.add(dotoutput.toString());
175        if (file != null) {
176            args.add(file.getPath());
177        }
178
179        Map<String,String> result = jdeps(args, dotfile);
180        checkResult("dependencies", expect, result.keySet());
181
182        // with -P option
183        List<String> argsWithDashP = new ArrayList<>();
184        argsWithDashP.add("-dotoutput");
185        argsWithDashP.add(dotoutput.toString());
186        argsWithDashP.add("-P");
187        argsWithDashP.addAll(args);
188
189        result = jdeps(argsWithDashP, dotfile);
190        checkResult("profiles", expect, profiles, result);
191    }
192
193    Map<String,String> jdeps(List<String> args, Path dotfile) throws IOException {
194        if (Files.exists(dotoutput)) {
195            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dotoutput)) {
196                for (Path p : stream) {
197                    Files.delete(p);
198                }
199            }
200            Files.delete(dotoutput);
201        }
202        // invoke jdeps
203        StringWriter sw = new StringWriter();
204        PrintWriter pw = new PrintWriter(sw);
205        System.err.println("jdeps " + args);
206        int rc = com.sun.tools.jdeps.Main.run(args.toArray(new String[0]), pw);
207        pw.close();
208        String out = sw.toString();
209        if (!out.isEmpty())
210            System.err.println(out);
211        if (rc != 0)
212            throw new Error("jdeps failed: rc=" + rc);
213
214        // check output files
215        if (Files.notExists(dotfile)) {
216            throw new RuntimeException(dotfile + " doesn't exist");
217        }
218        return parse(dotfile);
219    }
220    private static Pattern pattern = Pattern.compile("(.*) -> +([^ ]*) (.*)");
221    private Map<String,String> parse(Path outfile) throws IOException {
222        Map<String,String> result = new LinkedHashMap<>();
223        for (String line : Files.readAllLines(outfile)) {
224            line = line.replace('"', ' ').replace(';', ' ');
225            Matcher pm = pattern.matcher(line);
226            if (pm.find()) {
227                String origin = pm.group(1).trim();
228                String target = pm.group(2).trim();
229                String module = pm.group(3).replace('(', ' ').replace(')', ' ').trim();
230                result.put(target, module);
231            }
232        }
233        return result;
234    }
235
236    void checkResult(String label, String[] expect, Collection<String> found) {
237        List<String> list = Arrays.asList(expect);
238        if (!isEqual(list, found))
239            error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'");
240    }
241
242    void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) {
243        if (expect.length != profiles.length)
244            error("Invalid expected names and profiles");
245
246        // check the dependencies
247        checkResult(label, expect, result.keySet());
248        // check profile information
249        checkResult(label, profiles, result.values());
250        for (int i=0; i < expect.length; i++) {
251            String profile = result.get(expect[i]);
252            if (!profile.equals(profiles[i]))
253                error("Unexpected profile: '" + profile + "', expected: '" + profiles[i] + "'");
254        }
255    }
256
257    boolean isEqual(List<String> expected, Collection<String> found) {
258        if (expected.size() != found.size())
259            return false;
260
261        List<String> list = new ArrayList<>(found);
262        list.removeAll(expected);
263        return list.isEmpty();
264    }
265
266    void error(String msg) {
267        System.err.println("Error: " + msg);
268        errors++;
269    }
270
271    int errors;
272}
273