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