1 /* 2 * Copyright (c) 2010, 2013, 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 6968063 7127924 27 * @summary provide examples of code that generate diagnostics 28 * @build Example CheckExamples DocCommentProcessor 29 * @run main/othervm CheckExamples 30 */ 31 32 /* 33 * See CR 7127924 for info on why othervm is used. 34 */ 35 36 import java.io.*; 37 import java.nio.file.*; 38 import java.nio.file.attribute.BasicFileAttributes; 39 import java.util.*; 40 41 /** 42 * Check invariants for a set of examples. 43 * -- each example should exactly declare the keys that will be generated when 44 * it is run. 45 * -- together, the examples should cover the set of resource keys in the 46 * compiler.properties bundle. A list of exceptions may be given in the 47 * not-yet.txt file. Entries on the not-yet.txt list should not be 48 * covered by examples. 49 * When new keys are added to the resource bundle, it is strongly recommended 50 * that corresponding new examples be added here, if at all practical, instead 51 * of simply and lazily being added to the not-yet.txt list. 52 */ 53 public class CheckExamples { 54 /** 55 * Standard entry point. 56 */ main(String... args)57 public static void main(String... args) throws Exception { 58 boolean jtreg = (System.getProperty("test.src") != null); 59 Path tmpDir; 60 boolean deleteOnExit; 61 if (jtreg) { 62 // use standard jtreg scratch directory: the current directory 63 tmpDir = Paths.get(System.getProperty("user.dir")); 64 deleteOnExit = false; 65 } else { 66 tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), 67 CheckExamples.class.getName()); 68 deleteOnExit = true; 69 } 70 Example.setTempDir(tmpDir.toFile()); 71 72 try { 73 new CheckExamples().run(); 74 } finally { 75 if (deleteOnExit) { 76 clean(tmpDir); 77 } 78 } 79 } 80 81 /** 82 * Run the test. 83 */ run()84 void run() throws Exception { 85 Set<Example> examples = getExamples(); 86 87 Set<String> notYetList = getNotYetList(); 88 Set<String> declaredKeys = new TreeSet<String>(); 89 for (Example e: examples) { 90 Set<String> e_decl = e.getDeclaredKeys(); 91 Set<String> e_actual = e.getActualKeys(); 92 for (String k: e_decl) { 93 if (!e_actual.contains(k)) 94 error("Example " + e + " declares key " + k + " but does not generate it"); 95 } 96 for (String k: e_actual) { 97 if (!e_decl.contains(k)) 98 error("Example " + e + " generates key " + k + " but does not declare it"); 99 } 100 for (String k: e.getDeclaredKeys()) { 101 if (notYetList.contains(k)) 102 error("Example " + e + " declares key " + k + " which is also on the \"not yet\" list"); 103 declaredKeys.add(k); 104 } 105 } 106 107 ResourceBundle b = 108 ResourceBundle.getBundle("com.sun.tools.javac.resources.compiler"); 109 Set<String> resourceKeys = new TreeSet<String>(b.keySet()); 110 111 for (String dk: declaredKeys) { 112 if (!resourceKeys.contains(dk)) 113 error("Key " + dk + " is declared in tests but is not a valid key in resource bundle"); 114 } 115 116 for (String nk: notYetList) { 117 if (!resourceKeys.contains(nk)) 118 error("Key " + nk + " is declared in not-yet list but is not a valid key in resource bundle"); 119 } 120 121 for (String rk: resourceKeys) { 122 if (!declaredKeys.contains(rk) && !notYetList.contains(rk)) 123 error("Key " + rk + " is declared in resource bundle but is not in tests or not-yet list"); 124 } 125 126 System.err.println(examples.size() + " examples checked"); 127 System.err.println(notYetList.size() + " keys on not-yet list"); 128 129 Counts declaredCounts = new Counts(declaredKeys); 130 Counts resourceCounts = new Counts(resourceKeys); 131 List<String> rows = new ArrayList<String>(Arrays.asList(Counts.prefixes)); 132 rows.add("other"); 133 rows.add("total"); 134 System.err.println(); 135 System.err.println(String.format("%-14s %15s %15s %4s", 136 "prefix", "#keys in tests", "#keys in javac", "%")); 137 for (String p: rows) { 138 int d = declaredCounts.get(p); 139 int r = resourceCounts.get(p); 140 System.err.print(String.format("%-14s %15d %15d", p, d, r)); 141 if (r != 0) 142 System.err.print(String.format(" %3d%%", (d * 100) / r)); 143 System.err.println(); 144 } 145 146 if (errors > 0) 147 throw new Exception(errors + " errors occurred."); 148 } 149 150 /** 151 * Get the complete set of examples to be checked. 152 */ getExamples()153 Set<Example> getExamples() { 154 Set<Example> results = new TreeSet<Example>(); 155 File testSrc = new File(System.getProperty("test.src")); 156 File examples = new File(testSrc, "examples"); 157 for (File f: examples.listFiles()) { 158 if (isValidExample(f)) 159 results.add(new Example(f)); 160 } 161 return results; 162 } 163 isValidExample(File f)164 boolean isValidExample(File f) { 165 return (f.isDirectory() && f.list().length > 0) || 166 (f.isFile() && f.getName().endsWith(".java")); 167 } 168 169 /** 170 * Get the contents of the "not-yet" list. 171 */ getNotYetList()172 Set<String> getNotYetList() { 173 Set<String> results = new TreeSet<String>(); 174 File testSrc = new File(System.getProperty("test.src")); 175 File notYetList = new File(testSrc, "examples.not-yet.txt"); 176 try { 177 String[] lines = read(notYetList).split("[\r\n]"); 178 for (String line: lines) { 179 int hash = line.indexOf("#"); 180 if (hash != -1) 181 line = line.substring(0, hash).trim(); 182 if (line.matches("[A-Za-z0-9-_.]+")) 183 results.add(line); 184 } 185 } catch (IOException e) { 186 throw new Error(e); 187 } 188 return results; 189 } 190 191 /** 192 * Read the contents of a file. 193 */ read(File f)194 String read(File f) throws IOException { 195 byte[] bytes = new byte[(int) f.length()]; 196 DataInputStream in = new DataInputStream(new FileInputStream(f)); 197 try { 198 in.readFully(bytes); 199 } finally { 200 in.close(); 201 } 202 return new String(bytes); 203 } 204 205 /** 206 * Report an error. 207 */ error(String msg)208 void error(String msg) { 209 System.err.println("Error: " + msg); 210 errors++; 211 } 212 213 int errors; 214 215 /** 216 * Clean the contents of a directory. 217 */ clean(Path dir)218 static void clean(Path dir) throws IOException { 219 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 220 @Override 221 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 222 Files.delete(file); 223 return super.visitFile(file, attrs); 224 } 225 226 @Override 227 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 228 if (exc == null) Files.delete(dir); 229 return super.postVisitDirectory(dir, exc); 230 } 231 }); 232 } 233 234 static class Counts { 235 static String[] prefixes = { 236 "compiler.err.", 237 "compiler.warn.", 238 "compiler.note.", 239 "compiler.misc." 240 }; 241 Counts(Set<String> keys)242 Counts(Set<String> keys) { 243 nextKey: 244 for (String k: keys) { 245 for (String p: prefixes) { 246 if (k.startsWith(p)) { 247 inc(p); 248 continue nextKey; 249 } 250 } 251 inc("other"); 252 } 253 table.put("total", keys.size()); 254 } 255 get(String p)256 int get(String p) { 257 Integer i = table.get(p); 258 return (i == null ? 0 : i); 259 } 260 inc(String p)261 void inc(String p) { 262 Integer i = table.get(p); 263 table.put(p, (i == null ? 1 : i + 1)); 264 } 265 266 Map<String,Integer> table = new HashMap<String,Integer>(); 267 }; 268 } 269