APIDeps.java revision 2942:08092deced3f
1189251Ssam/* 2189251Ssam * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3189251Ssam * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4189251Ssam * 5252726Srpaulo * This code is free software; you can redistribute it and/or modify it 6252726Srpaulo * under the terms of the GNU General Public License version 2 only, as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * This code is distributed in the hope that it will be useful, but WITHOUT 10189251Ssam * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11189251Ssam * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12189251Ssam * version 2 for more details (a copy is included in the LICENSE file that 13189251Ssam * accompanied this code). 14189251Ssam * 15189251Ssam * You should have received a copy of the GNU General Public License version 16281806Srpaulo * 2 along with this work; if not, write to the Free Software Foundation, 17189251Ssam * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18189251Ssam * 19189251Ssam * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20189251Ssam * or visit www.oracle.com if you need additional information or have any 21189251Ssam * questions. 22189251Ssam */ 23189251Ssam 24189251Ssam/* 25189251Ssam * @test 26189251Ssam * @bug 8015912 8029216 8048063 8050804 27189251Ssam * @summary Test -apionly and -jdkinternals options 28189251Ssam * @modules java.base/sun.misc 29281806Srpaulo * java.management 30189251Ssam * jdk.jdeps/com.sun.tools.classfile 31281806Srpaulo * jdk.jdeps/com.sun.tools.jdeps 32189251Ssam * @build m.Bar m.Foo m.Gee b.B c.C c.I d.D e.E f.F g.G 33189251Ssam * @run main APIDeps 34189251Ssam */ 35189251Ssam 36189251Ssamimport java.io.File; 37189251Ssamimport java.io.IOException; 38189251Ssamimport java.io.PrintWriter; 39189251Ssamimport java.io.StringWriter; 40189251Ssamimport java.nio.file.Path; 41189251Ssamimport java.nio.file.Paths; 42189251Ssamimport java.util.*; 43189251Ssamimport java.util.regex.*; 44189251Ssam 45189251Ssampublic class APIDeps { 46189251Ssam public static void main(String... args) throws Exception { 47189251Ssam int errors = 0; 48189251Ssam errors += new APIDeps().run(); 49189251Ssam if (errors > 0) 50189251Ssam throw new Exception(errors + " errors found"); 51189251Ssam } 52189251Ssam 53189251Ssam int run() throws IOException { 54189251Ssam File testDir = new File(System.getProperty("test.classes", ".")); 55189251Ssam String testDirBasename = testDir.toPath().getFileName().toString(); 56189251Ssam File mDir = new File(testDir, "m"); 57189251Ssam // all dependencies 58189251Ssam test(new File(mDir, "Bar.class"), 59189251Ssam new String[] {"java.lang.Object", "java.lang.String", 60189251Ssam "java.util.Set", "java.util.HashSet", 61189251Ssam "java.lang.management.ManagementFactory", 62189251Ssam "java.lang.management.RuntimeMXBean", 63189251Ssam "b.B", "c.C", "d.D", "f.F", "g.G"}, 64189251Ssam new String[] {"compact1", "compact3", testDirBasename}, 65189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); 66189251Ssam test(new File(mDir, "Foo.class"), 67189251Ssam new String[] {"c.I", "e.E", "f.F"}, 68189251Ssam new String[] {testDirBasename}, 69189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P"}); 70189251Ssam test(new File(mDir, "Foo.class"), 71189251Ssam new String[] {"c.I", "e.E", "f.F", "m.Bar"}, 72189251Ssam new String[] {testDirBasename}, 73189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-filter:none", "-P"}); 74189251Ssam test(new File(mDir, "Gee.class"), 75189251Ssam new String[] {"g.G", "sun.misc.Lock", "com.sun.tools.classfile.ClassFile", 76189251Ssam "com.sun.management.ThreadMXBean", "com.sun.source.tree.BinaryTree"}, 77189251Ssam new String[] {testDirBasename, "JDK internal API", "compact3", ""}, 78189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); 79189251Ssam 80189251Ssam // -jdkinternals 81189251Ssam test(new File(mDir, "Gee.class"), 82189251Ssam new String[] {"sun.misc.Lock", "com.sun.tools.classfile.ClassFile"}, 83189251Ssam new String[] {"JDK internal API"}, 84189251Ssam new String[] {"-jdkinternals"}); 85189251Ssam // -jdkinternals parses all classes on -classpath and the input arguments 86189251Ssam test(new File(mDir, "Gee.class"), 87189251Ssam new String[] {"com.sun.tools.jdeps.Main", "com.sun.tools.classfile.ClassFile", 88189251Ssam "sun.misc.Lock", "sun.misc.Unsafe"}, 89189251Ssam new String[] {"JDK internal API"}, 90189251Ssam new String[] {"-classpath", testDir.getPath(), "-jdkinternals"}); 91189251Ssam 92189251Ssam // parse only APIs 93189251Ssam test(mDir, 94189251Ssam new String[] {"java.lang.Object", "java.lang.String", 95189251Ssam "java.util.Set", 96189251Ssam "c.C", "d.D", "c.I", "e.E"}, 97189251Ssam new String[] {"compact1", testDirBasename}, 98189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P", "-apionly"}); 99189251Ssam 100189251Ssam test(mDir, 101189251Ssam new String[] {"java.lang.Object", "java.lang.String", 102189251Ssam "java.util.Set", 103189251Ssam "c.C", "d.D", "c.I", "e.E", "m.Bar"}, 104189251Ssam new String[] {"compact1", testDirBasename, mDir.getName()}, 105189251Ssam new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"}); 106189251Ssam return errors; 107337817Scy } 108189251Ssam 109189251Ssam void test(File file, String[] expect, String[] profiles) { 110189251Ssam test(file, expect, profiles, new String[0]); 111189251Ssam } 112189251Ssam 113189251Ssam void test(File file, String[] expect, String[] profiles, String[] options) { 114189251Ssam List<String> args = new ArrayList<>(Arrays.asList(options)); 115189251Ssam if (file != null) { 116189251Ssam args.add(file.getPath()); 117189251Ssam } 118189251Ssam checkResult("api-dependencies", expect, profiles, 119189251Ssam jdeps(args.toArray(new String[0]))); 120189251Ssam } 121189251Ssam 122189251Ssam Map<String,String> jdeps(String... args) { 123189251Ssam StringWriter sw = new StringWriter(); 124189251Ssam PrintWriter pw = new PrintWriter(sw); 125189251Ssam System.err.println("jdeps " + Arrays.toString(args)); 126189251Ssam int rc = com.sun.tools.jdeps.Main.run(args, pw); 127189251Ssam pw.close(); 128189251Ssam String out = sw.toString(); 129346981Scy if (!out.isEmpty()) 130346981Scy System.err.println(out); 131189251Ssam if (rc != 0) 132189251Ssam throw new Error("jdeps failed: rc=" + rc); 133189251Ssam return findDeps(out); 134189251Ssam } 135189251Ssam 136189251Ssam // Pattern used to parse lines 137189251Ssam private static Pattern linePattern = Pattern.compile(".*\r?\n"); 138189251Ssam private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +(.*)"); 139337817Scy 140189251Ssam // Use the linePattern to break the given String into lines, applying 141189251Ssam // the pattern to each line to see if we have a match 142189251Ssam private static Map<String,String> findDeps(String out) { 143189251Ssam Map<String,String> result = new HashMap<>(); 144189251Ssam Matcher lm = linePattern.matcher(out); // Line matcher 145189251Ssam Matcher pm = null; // Pattern matcher 146189251Ssam int lines = 0; 147189251Ssam while (lm.find()) { 148189251Ssam lines++; 149189251Ssam CharSequence cs = lm.group(); // The current line 150189251Ssam if (pm == null) 151189251Ssam pm = pattern.matcher(cs); 152189251Ssam else 153189251Ssam pm.reset(cs); 154189251Ssam if (pm.find()) 155189251Ssam result.put(pm.group(1), pm.group(2).trim()); 156189251Ssam if (lm.end() == out.length()) 157189251Ssam break; 158189251Ssam } 159189251Ssam return result; 160189251Ssam } 161189251Ssam 162189251Ssam void checkResult(String label, String[] expect, Collection<String> found) { 163189251Ssam List<String> list = Arrays.asList(expect); 164189251Ssam if (!isEqual(list, found)) 165189251Ssam error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'"); 166189251Ssam } 167189251Ssam 168189251Ssam void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) { 169189251Ssam // check the dependencies 170189251Ssam checkResult(label, expect, result.keySet()); 171189251Ssam // check profile information 172189251Ssam Set<String> values = new TreeSet<>(); 173189251Ssam String internal = "JDK internal API"; 174189251Ssam for (String s: result.values()) { 175189251Ssam if (s.startsWith(internal)){ 176189251Ssam values.add(internal); 177189251Ssam } else { 178189251Ssam values.add(s); 179189251Ssam } 180189251Ssam } 181189251Ssam checkResult(label, profiles, values); 182189251Ssam } 183189251Ssam 184337817Scy boolean isEqual(List<String> expected, Collection<String> found) { 185189251Ssam if (expected.size() != found.size()) 186189251Ssam return false; 187189251Ssam 188189251Ssam List<String> list = new ArrayList<>(found); 189189251Ssam list.removeAll(expected); 190189251Ssam return list.isEmpty(); 191189251Ssam } 192189251Ssam 193189251Ssam void error(String msg) { 194189251Ssam System.err.println("Error: " + msg); 195189251Ssam errors++; 196189251Ssam } 197189251Ssam 198189251Ssam int errors; 199189251Ssam} 200189251Ssam