Fri, 28 Apr 2017 14:30:11 -0700
Merge
mchung@2139 | 1 | /* |
mchung@2538 | 2 | * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. |
mchung@2139 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
mchung@2139 | 4 | * |
mchung@2139 | 5 | * This code is free software; you can redistribute it and/or modify it |
mchung@2139 | 6 | * under the terms of the GNU General Public License version 2 only, as |
mchung@2139 | 7 | * published by the Free Software Foundation. |
mchung@2139 | 8 | * |
mchung@2139 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
mchung@2139 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
mchung@2139 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
mchung@2139 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
mchung@2139 | 13 | * accompanied this code). |
mchung@2139 | 14 | * |
mchung@2139 | 15 | * You should have received a copy of the GNU General Public License version |
mchung@2139 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
mchung@2139 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
mchung@2139 | 18 | * |
mchung@2139 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
mchung@2139 | 20 | * or visit www.oracle.com if you need additional information or have any |
mchung@2139 | 21 | * questions. |
mchung@2139 | 22 | */ |
mchung@2139 | 23 | |
mchung@2139 | 24 | /* |
mchung@2139 | 25 | * @test |
mchung@2539 | 26 | * @bug 8015912 8029216 8048063 8050804 |
mchung@2214 | 27 | * @summary Test -apionly and -jdkinternals options |
mchung@2139 | 28 | * @build m.Bar m.Foo m.Gee b.B c.C c.I d.D e.E f.F g.G |
mchung@2139 | 29 | * @run main APIDeps |
mchung@2139 | 30 | */ |
mchung@2139 | 31 | |
mchung@2139 | 32 | import java.io.File; |
mchung@2139 | 33 | import java.io.IOException; |
mchung@2139 | 34 | import java.io.PrintWriter; |
mchung@2139 | 35 | import java.io.StringWriter; |
mchung@2139 | 36 | import java.nio.file.Path; |
mchung@2139 | 37 | import java.nio.file.Paths; |
mchung@2139 | 38 | import java.util.*; |
mchung@2139 | 39 | import java.util.regex.*; |
mchung@2139 | 40 | |
mchung@2139 | 41 | public class APIDeps { |
mchung@2139 | 42 | private static boolean symbolFileExist = initProfiles(); |
mchung@2139 | 43 | private static boolean initProfiles() { |
mchung@2139 | 44 | // check if ct.sym exists; if not use the profiles.properties file |
mchung@2139 | 45 | Path home = Paths.get(System.getProperty("java.home")); |
mchung@2139 | 46 | if (home.endsWith("jre")) { |
mchung@2139 | 47 | home = home.getParent(); |
mchung@2139 | 48 | } |
mchung@2139 | 49 | Path ctsym = home.resolve("lib").resolve("ct.sym"); |
mchung@2139 | 50 | boolean symbolExists = ctsym.toFile().exists(); |
mchung@2139 | 51 | if (!symbolExists) { |
mchung@2139 | 52 | Path testSrcProfiles = |
mchung@2139 | 53 | Paths.get(System.getProperty("test.src", "."), "profiles.properties"); |
mchung@2139 | 54 | if (!testSrcProfiles.toFile().exists()) |
mchung@2139 | 55 | throw new Error(testSrcProfiles + " does not exist"); |
mchung@2139 | 56 | System.out.format("%s doesn't exist.%nUse %s to initialize profiles info%n", |
mchung@2139 | 57 | ctsym, testSrcProfiles); |
mchung@2139 | 58 | System.setProperty("jdeps.profiles", testSrcProfiles.toString()); |
mchung@2139 | 59 | } |
mchung@2139 | 60 | return symbolExists; |
mchung@2139 | 61 | } |
mchung@2139 | 62 | |
mchung@2139 | 63 | public static void main(String... args) throws Exception { |
mchung@2139 | 64 | int errors = 0; |
mchung@2139 | 65 | errors += new APIDeps().run(); |
mchung@2139 | 66 | if (errors > 0) |
mchung@2139 | 67 | throw new Exception(errors + " errors found"); |
mchung@2139 | 68 | } |
mchung@2139 | 69 | |
mchung@2139 | 70 | int run() throws IOException { |
mchung@2139 | 71 | File testDir = new File(System.getProperty("test.classes", ".")); |
mchung@2139 | 72 | String testDirBasename = testDir.toPath().getFileName().toString(); |
mchung@2139 | 73 | File mDir = new File(testDir, "m"); |
mchung@2139 | 74 | // all dependencies |
mchung@2139 | 75 | test(new File(mDir, "Bar.class"), |
mchung@2139 | 76 | new String[] {"java.lang.Object", "java.lang.String", |
mchung@2139 | 77 | "java.util.Set", "java.util.HashSet", |
mchung@2139 | 78 | "java.lang.management.ManagementFactory", |
mchung@2139 | 79 | "java.lang.management.RuntimeMXBean", |
mchung@2139 | 80 | "b.B", "c.C", "d.D", "f.F", "g.G"}, |
mchung@2139 | 81 | new String[] {"compact1", "compact3", testDirBasename}, |
mchung@2139 | 82 | new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); |
mchung@2139 | 83 | test(new File(mDir, "Foo.class"), |
mchung@2538 | 84 | new String[] {"c.I", "e.E", "f.F"}, |
mchung@2538 | 85 | new String[] {testDirBasename}, |
mchung@2538 | 86 | new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P"}); |
mchung@2538 | 87 | test(new File(mDir, "Foo.class"), |
mchung@2139 | 88 | new String[] {"c.I", "e.E", "f.F", "m.Bar"}, |
mchung@2139 | 89 | new String[] {testDirBasename}, |
mchung@2538 | 90 | new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-filter:none", "-P"}); |
mchung@2538 | 91 | test(new File(mDir, "Gee.class"), |
mchung@2538 | 92 | new String[] {"g.G", "sun.misc.Lock", "com.sun.tools.classfile.ClassFile", |
mchung@2803 | 93 | "com.sun.management.ThreadMXBean", "com.sun.source.tree.BinaryTree", |
mchung@2803 | 94 | "org.w3c.dom.css.CSSValue"}, |
mchung@2803 | 95 | new String[] {testDirBasename, "JDK internal API", "compact2", "compact3", ""}, |
mchung@2139 | 96 | new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"}); |
mchung@2214 | 97 | |
mchung@2214 | 98 | // -jdkinternals |
mchung@2214 | 99 | test(new File(mDir, "Gee.class"), |
mchung@2538 | 100 | new String[] {"sun.misc.Lock", "com.sun.tools.classfile.ClassFile"}, |
mchung@2214 | 101 | new String[] {"JDK internal API"}, |
mchung@2214 | 102 | new String[] {"-jdkinternals"}); |
mchung@2214 | 103 | // -jdkinternals parses all classes on -classpath and the input arguments |
mchung@2214 | 104 | test(new File(mDir, "Gee.class"), |
mchung@2538 | 105 | new String[] {"com.sun.tools.jdeps.Main", "com.sun.tools.classfile.ClassFile", |
mchung@2538 | 106 | "sun.misc.Lock", "sun.misc.Unsafe"}, |
mchung@2214 | 107 | new String[] {"JDK internal API"}, |
mchung@2214 | 108 | new String[] {"-classpath", testDir.getPath(), "-jdkinternals"}); |
mchung@2214 | 109 | |
mchung@2214 | 110 | // parse only APIs |
mchung@2538 | 111 | test(mDir, |
mchung@2538 | 112 | new String[] {"java.lang.Object", "java.lang.String", |
mchung@2538 | 113 | "java.util.Set", |
mchung@2538 | 114 | "c.C", "d.D", "c.I", "e.E"}, |
mchung@2538 | 115 | new String[] {"compact1", testDirBasename}, |
mchung@2538 | 116 | new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-P", "-apionly"}); |
mchung@2538 | 117 | |
mchung@2139 | 118 | test(mDir, |
mchung@2139 | 119 | new String[] {"java.lang.Object", "java.lang.String", |
mchung@2139 | 120 | "java.util.Set", |
mchung@2139 | 121 | "c.C", "d.D", "c.I", "e.E", "m.Bar"}, |
mchung@2139 | 122 | new String[] {"compact1", testDirBasename, mDir.getName()}, |
mchung@2139 | 123 | new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"}); |
mchung@2139 | 124 | return errors; |
mchung@2139 | 125 | } |
mchung@2139 | 126 | |
mchung@2139 | 127 | void test(File file, String[] expect, String[] profiles) { |
mchung@2139 | 128 | test(file, expect, profiles, new String[0]); |
mchung@2139 | 129 | } |
mchung@2139 | 130 | |
mchung@2139 | 131 | void test(File file, String[] expect, String[] profiles, String[] options) { |
mchung@2139 | 132 | List<String> args = new ArrayList<>(Arrays.asList(options)); |
mchung@2139 | 133 | if (file != null) { |
mchung@2139 | 134 | args.add(file.getPath()); |
mchung@2139 | 135 | } |
mchung@2139 | 136 | checkResult("api-dependencies", expect, profiles, |
mchung@2139 | 137 | jdeps(args.toArray(new String[0]))); |
mchung@2139 | 138 | } |
mchung@2139 | 139 | |
mchung@2139 | 140 | Map<String,String> jdeps(String... args) { |
mchung@2139 | 141 | StringWriter sw = new StringWriter(); |
mchung@2139 | 142 | PrintWriter pw = new PrintWriter(sw); |
mchung@2139 | 143 | System.err.println("jdeps " + Arrays.toString(args)); |
mchung@2139 | 144 | int rc = com.sun.tools.jdeps.Main.run(args, pw); |
mchung@2139 | 145 | pw.close(); |
mchung@2139 | 146 | String out = sw.toString(); |
mchung@2139 | 147 | if (!out.isEmpty()) |
mchung@2139 | 148 | System.err.println(out); |
mchung@2139 | 149 | if (rc != 0) |
mchung@2139 | 150 | throw new Error("jdeps failed: rc=" + rc); |
mchung@2139 | 151 | return findDeps(out); |
mchung@2139 | 152 | } |
mchung@2139 | 153 | |
mchung@2139 | 154 | // Pattern used to parse lines |
mchung@2139 | 155 | private static Pattern linePattern = Pattern.compile(".*\r?\n"); |
mchung@2139 | 156 | private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +(.*)"); |
mchung@2139 | 157 | |
mchung@2139 | 158 | // Use the linePattern to break the given String into lines, applying |
mchung@2139 | 159 | // the pattern to each line to see if we have a match |
mchung@2139 | 160 | private static Map<String,String> findDeps(String out) { |
mchung@2139 | 161 | Map<String,String> result = new HashMap<>(); |
mchung@2139 | 162 | Matcher lm = linePattern.matcher(out); // Line matcher |
mchung@2139 | 163 | Matcher pm = null; // Pattern matcher |
mchung@2139 | 164 | int lines = 0; |
mchung@2139 | 165 | while (lm.find()) { |
mchung@2139 | 166 | lines++; |
mchung@2139 | 167 | CharSequence cs = lm.group(); // The current line |
mchung@2139 | 168 | if (pm == null) |
mchung@2139 | 169 | pm = pattern.matcher(cs); |
mchung@2139 | 170 | else |
mchung@2139 | 171 | pm.reset(cs); |
mchung@2139 | 172 | if (pm.find()) |
mchung@2139 | 173 | result.put(pm.group(1), pm.group(2).trim()); |
mchung@2139 | 174 | if (lm.end() == out.length()) |
mchung@2139 | 175 | break; |
mchung@2139 | 176 | } |
mchung@2139 | 177 | return result; |
mchung@2139 | 178 | } |
mchung@2139 | 179 | |
mchung@2139 | 180 | void checkResult(String label, String[] expect, Collection<String> found) { |
mchung@2139 | 181 | List<String> list = Arrays.asList(expect); |
mchung@2139 | 182 | if (!isEqual(list, found)) |
mchung@2139 | 183 | error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'"); |
mchung@2139 | 184 | } |
mchung@2139 | 185 | |
mchung@2139 | 186 | void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) { |
mchung@2139 | 187 | // check the dependencies |
mchung@2139 | 188 | checkResult(label, expect, result.keySet()); |
mchung@2139 | 189 | // check profile information |
mchung@2139 | 190 | Set<String> values = new TreeSet<>(); |
mchung@2139 | 191 | String internal = "JDK internal API"; |
mchung@2139 | 192 | for (String s: result.values()) { |
mchung@2139 | 193 | if (s.startsWith(internal)){ |
mchung@2139 | 194 | values.add(internal); |
mchung@2139 | 195 | } else { |
mchung@2139 | 196 | values.add(s); |
mchung@2139 | 197 | } |
mchung@2139 | 198 | } |
mchung@2139 | 199 | checkResult(label, profiles, values); |
mchung@2139 | 200 | } |
mchung@2139 | 201 | |
mchung@2139 | 202 | boolean isEqual(List<String> expected, Collection<String> found) { |
mchung@2139 | 203 | if (expected.size() != found.size()) |
mchung@2139 | 204 | return false; |
mchung@2139 | 205 | |
mchung@2139 | 206 | List<String> list = new ArrayList<>(found); |
mchung@2139 | 207 | list.removeAll(expected); |
mchung@2139 | 208 | return list.isEmpty(); |
mchung@2139 | 209 | } |
mchung@2139 | 210 | |
mchung@2139 | 211 | void error(String msg) { |
mchung@2139 | 212 | System.err.println("Error: " + msg); |
mchung@2139 | 213 | errors++; |
mchung@2139 | 214 | } |
mchung@2139 | 215 | |
mchung@2139 | 216 | int errors; |
mchung@2139 | 217 | } |