test/langtools/tools/jdeps/APIDeps.java
changeset 47216 71c04702a3d5
parent 43258 45757c4367f2
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2012, 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  * @bug 8015912 8029216 8048063 8050804
       
    27  * @summary Test -apionly and -jdkinternals options
       
    28  * @library lib
       
    29  * @modules java.base/sun.security.x509
       
    30  *          java.management
       
    31  *          jdk.jdeps/com.sun.tools.classfile
       
    32  *          jdk.jdeps/com.sun.tools.jdeps
       
    33  * @run main APIDeps
       
    34  */
       
    35 
       
    36 import java.io.File;
       
    37 import java.io.IOException;
       
    38 import java.io.PrintWriter;
       
    39 import java.io.StringWriter;
       
    40 import java.nio.file.*;
       
    41 import java.util.*;
       
    42 import java.util.regex.*;
       
    43 import java.util.stream.Collectors;
       
    44 
       
    45 public class APIDeps {
       
    46     public static void main(String... args) throws Exception {
       
    47         int errors = 0;
       
    48         errors += new APIDeps().run();
       
    49         if (errors > 0)
       
    50             throw new Exception(errors + " errors found");
       
    51     }
       
    52 
       
    53     private static final Path dest = Paths.get(System.getProperty("test.classes", "."), "tmp");
       
    54     private static final String[] srcDirs = new String[] {
       
    55             "m", "b", "c", "d", "e", "f", "g"
       
    56     };
       
    57     void setup(Path dest) throws IOException {
       
    58         CompilerUtils.cleanDir(dest);
       
    59         Files.createDirectories(dest);
       
    60         Path testsrc = Paths.get(System.getProperty("test.src"));
       
    61         List<String> options = new ArrayList<>();
       
    62 
       
    63         // jdk.jdeps is a service provider module so needs to be explicitly included
       
    64         options.add("--add-modules=jdk.jdeps");
       
    65 
       
    66         // add --add-exports
       
    67         String testModules = System.getProperty("test.modules", "");
       
    68         List<String> addExports = new ArrayList<>();
       
    69         for (String s : testModules.split("\\s+")) {
       
    70             if (s.isEmpty()) continue;
       
    71             if (s.indexOf('/') != -1)
       
    72                 addExports.add("--add-exports=" + s.trim() + "=ALL-UNNAMED");
       
    73         }
       
    74         options.addAll(addExports);
       
    75 
       
    76         for (String dir : srcDirs) {
       
    77             Path source = testsrc.resolve(dir);
       
    78             boolean ok = CompilerUtils.compile(source, dest, options.toArray(new String[0]));
       
    79             if (!ok) {
       
    80                 throw new RuntimeException("compilation fails");
       
    81             }
       
    82         }
       
    83     }
       
    84 
       
    85     int run() throws IOException {
       
    86         // compile classes in a separate directory for analysis
       
    87         setup(dest);
       
    88 
       
    89         File testDir = dest.toFile();
       
    90         String testDirBasename = testDir.toPath().getFileName().toString();
       
    91         File mDir = new File(testDir, "m");
       
    92         // all dependencies
       
    93         test(new File(mDir, "Bar.class"),
       
    94              new String[] {"java.lang.Object", "java.lang.String",
       
    95                            "java.util.Set", "java.util.HashSet",
       
    96                            "java.lang.management.ManagementFactory",
       
    97                            "java.lang.management.RuntimeMXBean",
       
    98                            "b.B", "c.C", "d.D", "f.F", "g.G"},
       
    99              new String[] {"compact1", "compact3", testDirBasename},
       
   100              new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"});
       
   101         test(new File(mDir, "Foo.class"),
       
   102              new String[] {"c.I", "e.E", "f.F"},
       
   103              new String[] {testDirBasename},
       
   104              new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P"});
       
   105         test(new File(mDir, "Foo.class"),
       
   106              new String[] {"c.I", "e.E", "f.F", "m.Bar"},
       
   107              new String[] {testDirBasename},
       
   108              new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-filter:none", "-P"});
       
   109         test(new File(mDir, "Gee.class"),
       
   110              new String[] {"g.G", "sun.security.x509.X509CertInfo", "com.sun.tools.classfile.ClassFile",
       
   111                            "com.sun.management.ThreadMXBean", "com.sun.source.tree.BinaryTree"},
       
   112              new String[] {testDirBasename, "JDK internal API", "compact3", ""},
       
   113              new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"});
       
   114 
       
   115         // -jdkinternals
       
   116         test(new File(mDir, "Gee.class"),
       
   117              new String[] {"sun.security.x509.X509CertInfo", "com.sun.tools.classfile.ClassFile"},
       
   118              new String[] {"JDK internal API"},
       
   119              new String[] {"-jdkinternals", "-quiet"});
       
   120         // -jdkinternals parses all classes on -classpath and the input arguments
       
   121         test(new File(mDir, "Gee.class"),
       
   122              new String[] {"com.sun.tools.classfile.ClassFile",
       
   123                            "sun.security.x509.X509CertInfo"},
       
   124              new String[] {"JDK internal API"},
       
   125              // use -classpath tmp/a with no use of JDK internal API
       
   126              new String[] {"-classpath", dest.resolve("a").toString(), "-jdkinternals", "-quiet"});
       
   127 
       
   128         // parse only APIs
       
   129         test(mDir,
       
   130              new String[] {"java.lang.Object", "java.lang.String",
       
   131                            "java.util.Set",
       
   132                            "c.C", "d.D", "c.I", "e.E"},
       
   133              new String[] {"compact1", testDirBasename},
       
   134              new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P", "-apionly"});
       
   135 
       
   136         test(mDir,
       
   137              new String[] {"java.lang.Object", "java.lang.String",
       
   138                            "java.util.Set",
       
   139                            "c.C", "d.D", "c.I", "e.E", "m.Bar"},
       
   140              new String[] {"compact1", testDirBasename, mDir.getName()},
       
   141              new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "--api-only"});
       
   142         return errors;
       
   143     }
       
   144 
       
   145     void test(File file, String[] expect, String[] profiles) {
       
   146         test(file, expect, profiles, new String[0]);
       
   147     }
       
   148 
       
   149     void test(File file, String[] expect, String[] profiles, String[] options) {
       
   150         List<String> args = new ArrayList<>(Arrays.asList(options));
       
   151         if (file != null) {
       
   152             args.add(file.getPath());
       
   153         }
       
   154         checkResult("api-dependencies", expect, profiles,
       
   155                     jdeps(args.toArray(new String[0])));
       
   156     }
       
   157 
       
   158     Map<String,String> jdeps(String... args) {
       
   159         StringWriter sw = new StringWriter();
       
   160         PrintWriter pw = new PrintWriter(sw);
       
   161         System.err.println("jdeps " + Arrays.stream(args)
       
   162             .collect(Collectors.joining(" ")));
       
   163         int rc = com.sun.tools.jdeps.Main.run(args, pw);
       
   164         pw.close();
       
   165         String out = sw.toString();
       
   166         if (!out.isEmpty())
       
   167             System.err.println(out);
       
   168         if (rc != 0)
       
   169             throw new Error("jdeps failed: rc=" + rc);
       
   170         return findDeps(out);
       
   171     }
       
   172 
       
   173     // Pattern used to parse lines
       
   174     private static Pattern linePattern = Pattern.compile(".*\r?\n");
       
   175     private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +(.*)");
       
   176 
       
   177     // Use the linePattern to break the given String into lines, applying
       
   178     // the pattern to each line to see if we have a match
       
   179     private static Map<String,String> findDeps(String out) {
       
   180         Map<String,String> result = new HashMap<>();
       
   181         Matcher lm = linePattern.matcher(out);  // Line matcher
       
   182         Matcher pm = null;                      // Pattern matcher
       
   183         int lines = 0;
       
   184         while (lm.find()) {
       
   185             lines++;
       
   186             CharSequence cs = lm.group();       // The current line
       
   187             if (pm == null)
       
   188                 pm = pattern.matcher(cs);
       
   189             else
       
   190                 pm.reset(cs);
       
   191             if (pm.find())
       
   192                 result.put(pm.group(1), pm.group(2).trim());
       
   193             if (lm.end() == out.length())
       
   194                 break;
       
   195         }
       
   196         return result;
       
   197     }
       
   198 
       
   199     void checkResult(String label, String[] expect, Collection<String> found) {
       
   200         List<String> list = Arrays.asList(expect);
       
   201         if (!isEqual(list, found))
       
   202             error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'");
       
   203     }
       
   204 
       
   205     void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) {
       
   206         // check the dependencies
       
   207         checkResult(label, expect, result.keySet());
       
   208         // check profile information
       
   209         Set<String> values = new TreeSet<>();
       
   210         String internal = "JDK internal API";
       
   211         for (String s: result.values()) {
       
   212             if (s.startsWith(internal)){
       
   213                 values.add(internal);
       
   214             } else {
       
   215                 values.add(s);
       
   216             }
       
   217         }
       
   218         checkResult(label, profiles, values);
       
   219     }
       
   220 
       
   221     boolean isEqual(List<String> expected, Collection<String> found) {
       
   222         if (expected.size() != found.size())
       
   223             return false;
       
   224 
       
   225         List<String> list = new ArrayList<>(found);
       
   226         list.removeAll(expected);
       
   227         return list.isEmpty();
       
   228     }
       
   229 
       
   230     void error(String msg) {
       
   231         System.err.println("Error: " + msg);
       
   232         errors++;
       
   233     }
       
   234 
       
   235     int errors;
       
   236 
       
   237 }