/* * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @bug 6968063 7127924 * @summary provide examples of code that generate diagnostics * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.parser * jdk.compiler/com.sun.tools.javac.util * @build ArgTypeCompilerFactory Example HTMLWriter RunExamples DocCommentProcessor * @run main/othervm RunExamples */ /* * See CR 7127924 for info on why othervm is used. */ import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Utility to run selected or all examples, writing results to * stdout, a plain text file or an HTML file. This program can be * run standalone, or as a jtreg test. * * Options: * -examples dir directory of examples. Defaults to ${test.src}/examples * -raw run examples with -XDrawDiagnostics * -showFiles include text of source files in the output * -verbose verbose output * -o file write output to file: format will be HTML if * file has .html extension; otherwise it will be plain text. * default is to stdout * -title string specify a title, only applies to HTML output */ public class RunExamples { public static void main(String... args) throws Exception { jtreg = (System.getProperty("test.src") != null); Path tmpDir; boolean deleteOnExit; if (jtreg) { // use standard jtreg scratch directory: the current directory tmpDir = Paths.get(System.getProperty("user.dir")); deleteOnExit = false; } else { tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), RunExamples.class.getName()); deleteOnExit = true; } Example.setTempDir(tmpDir.toFile()); RunExamples r = new RunExamples(); try { if (r.run(args)) return; } finally { if (deleteOnExit) { clean(tmpDir); } } if (jtreg) throw new Exception(r.errors + " errors occurred"); else System.exit(1); } boolean run(String... args) { Set<String> selectedKeys = new TreeSet<String>(); Set<Example> selectedExamples = new TreeSet<Example>(); File testSrc = new File(System.getProperty("test.src", ".")); File examplesDir = new File(testSrc, "examples"); File outFile = null; boolean raw = false; boolean showFiles = false; boolean verbose = false; boolean argTypes = false; String title = null; for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals("-k") && (i + 1) < args.length) selectedKeys.add(args[++i]); else if (arg.equals("-examples") && (i + 1) < args.length) examplesDir = new File(args[++i]); else if (arg.equals("-raw")) raw = true; else if (arg.equals("-showFiles")) showFiles = true; else if (arg.equals("-verbose")) verbose = true; else if (arg.equals("-o") && (i + 1) < args.length) outFile = new File(args[++i]); else if (arg.equals("-title") && (i + 1) < args.length) title = args[++i]; else if (arg.equals("-argtypes")) argTypes = true; else if (arg.startsWith("-")) { error("unknown option: " + arg); return false; } else { while (i < args.length) { File f = new File(examplesDir, args[i]); selectedExamples.add(new Example(f)); i++; } } } // special mode to show message keys and the types of the args that // are used. if (argTypes) Example.Compiler.factory = new ArgTypeCompilerFactory(); if (selectedKeys.size() > 0) { Set<Example> examples = getExamples(examplesDir); nextKey: for (String k: selectedKeys) { for (Example e: examples) { if (e.getDeclaredKeys().contains(k)) continue nextKey; } error("Key " + k + ": no examples found"); } } else { if (selectedExamples.isEmpty()) selectedExamples = getExamples(examplesDir); } try { Runner r; if (outFile == null) { PrintWriter out = new PrintWriter(System.out); r = new TextRunner(out, showFiles, raw, verbose); } else if (outFile.getName().endsWith(".html")) r = new HTMLRunner(outFile, showFiles, raw, verbose, title); else r = new TextRunner(outFile, showFiles, raw, verbose); r.run(selectedExamples); r.close(); } catch (IOException e) { error("Error writing output: " + e); } return (errors == 0); } /** * Get the complete set of examples to be checked. */ Set<Example> getExamples(File examplesDir) { Set<Example> results = new TreeSet<Example>(); for (File f: examplesDir.listFiles()) { if (isValidExample(f)) results.add(new Example(f)); } return results; } boolean isValidExample(File f) { return (f.isDirectory() && (!jtreg || f.list().length > 0)) || (f.isFile() && f.getName().endsWith(".java")); } /** * Report an error. */ void error(String msg) { System.err.println("Error: " + msg); errors++; } static boolean jtreg; int errors; /** * Clean the contents of a directory. */ static void clean(Path dir) throws IOException { Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return super.visitFile(file, attrs); } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (exc == null) Files.delete(dir); return super.postVisitDirectory(dir, exc); } }); } static abstract class Runner { Runner(boolean showFiles, boolean raw, boolean verbose) { this.showFiles = showFiles; this.raw = raw; this.verbose = verbose; } void close() throws IOException { } void run(Collection<Example> examples) throws IOException { for (Example e: examples) { startExample(e); if (showFiles) { showFile(e, e.infoFile); Set<File> srcFiles = new TreeSet<File>(e.srcFiles); srcFiles.remove(e.infoFile); showFiles(e, srcFiles); showFiles(e, e.srcPathFiles); showFiles(e, e.procFiles); showFiles(e, e.supportFiles); } run(e); } } void showFiles(Example e, Collection<File> files) throws IOException { for (File f: files) showFile(e, f); } abstract void startExample(Example e) throws IOException; abstract void showFile(Example e, File f) throws IOException; abstract void run(Example e) throws IOException; protected String read(File f) throws IOException { byte[] bytes = new byte[(int) f.length()]; DataInputStream in = new DataInputStream(new FileInputStream(f)); try { in.readFully(bytes); } finally { in.close(); } return new String(bytes); } protected Pattern copyrightHeaderPat = Pattern.compile("(?s)(/\\*.*?Copyright.*?\\*/\n)\\s*(.*)"); protected Pattern infoHeaderPat = Pattern.compile("(?s)((?://\\s*[a-z]+:[^\n]*\n)+)\\s*(.*)"); protected boolean showFiles; protected boolean raw; protected boolean verbose; } static class TextRunner extends Runner { TextRunner(File file, boolean showFiles, boolean raw, boolean verbose) throws IOException { super(showFiles, raw, verbose); this.file = file; out = new PrintWriter(new FileWriter(file)); } TextRunner(PrintWriter out, boolean showFiles, boolean raw, boolean verbose) throws IOException { super(showFiles, raw, verbose); this.out = out; } @Override void close() { if (file != null) out.close(); } @Override void startExample(Example e) { out.println("----- " + e.getName() + " --------------------"); out.println(); } @Override void showFile(Example e, File f) { out.println("--- " + f); String text; try { text = read(f); } catch (IOException ex) { text = "Error reading " + f + "; " + ex; } Matcher m = copyrightHeaderPat.matcher(text); if (m.matches()) { out.println("(Copyright)"); writeLines(m.group(2)); } else { writeLines(text); } out.println(); } @Override void run(Example e) { // only show Output: header if also showing files if (showFiles) out.println("--- Output:"); e.run(out, raw, verbose); out.println(); } void writeLines(String text) { for (String line: text.split("\n")) out.println(line); } File file; PrintWriter out; } static class HTMLRunner extends Runner { HTMLRunner(File file, boolean showFiles, boolean raw, boolean verbose, String title) throws IOException { super(showFiles, raw, verbose); this.file = file; PrintWriter out = new PrintWriter(new FileWriter(file)); html = new HTMLWriter(out); html.startTag(HTMLWriter.HEAD); if (title != null) { html.startTag(HTMLWriter.TITLE); html.write(title); html.endTag(HTMLWriter.TITLE); } html.startTag(HTMLWriter.META); html.writeAttr(HTMLWriter.CHARSET, "UTF-8"); html.startTag(HTMLWriter.STYLE); html.write(null); // revert to body text html.newLine(); html.writeLine("div.file { background-color:#e0ffe0; margin-left:30px; margin-right:30px;\n" + " padding: 3px; border: thin solid silver; }"); html.writeLine("p.file { white-space: pre-wrap; font-family:monospace; margin: 0; }"); html.writeLine("div.output { background-color:#e0e0ff; margin-left:30px; margin-right:30px;\n" + " padding: 3px; border: thin solid silver; }"); html.writeLine("p.output { white-space: pre-wrap; font-family:monospace; margin: 0; }"); html.writeLine("table.index { border: thin solid silver; }"); html.writeLine(".copyright { font-size: x-small }"); html.writeLine(".hidden { display:none }"); html.writeLine(".unhidden { display:block }"); html.writeLine(".odd { background-color: #e0e0e0 }"); html.writeLine(".even { background-color: white }"); html.endTag(HTMLWriter.STYLE); html.startTag(HTMLWriter.SCRIPT); html.writeAttr(HTMLWriter.TYPE, HTMLWriter.TEXT_JAVASCRIPT); html.writeLine("\nfunction unhide(id) {\n" + " var item = document.getElementById(id);\n" + " if (item) {\n" + " item.className=(item.className=='hidden')?'unhidden':'hidden';\n" + " }\n" + "}"); html.endTag(HTMLWriter.SCRIPT); html.endTag(HTMLWriter.HEAD); html.startTag(HTMLWriter.BODY); if (title != null) { html.startTag(TITLE_HEADER); html.write(title); html.endTag(TITLE_HEADER); } } @Override void close() throws IOException { html.endTag(HTMLWriter.BODY); html.newLine(); html.flush(); } @Override void run(Collection<Example> examples) throws IOException { if (examples.size() > 1) writeIndex(examples); super.run(examples); } void writeIndex(Collection<Example> examples) throws IOException { Map<String, Set<Example>> index = new TreeMap<String, Set<Example>>(); Set<String> initials = new HashSet<String>(); for (Example e: examples) { for (String k: e.getDeclaredKeys()) { Set<Example> s = index.get(k); if (s == null) index.put(k, s = new TreeSet<Example>()); s.add(e); } initials.add(e.getName().substring(0, 1).toUpperCase()); } if (INDEX_HEADER != null) { html.startTag(INDEX_HEADER); html.write("Index"); html.endTag(INDEX_HEADER); } html.startTag(HTMLWriter.P); html.writeLine("Examples: "); for (char initial = 'A'; initial <= 'Z'; initial++) { String s = String.valueOf(initial); if (initials.contains(s)) { html.writeLink("#" + s, s); } else { html.write(s); } html.newLine(); } html.endTag(HTMLWriter.P); html.startTag(HTMLWriter.TABLE); html.writeAttr(HTMLWriter.CLASS, "index"); html.newLine(); int row = 0; for (Map.Entry<String, Set<Example>> entry: index.entrySet()) { html.startTag(HTMLWriter.TR); html.writeAttr(HTMLWriter.CLASS, (row++ % 2 == 0 ? "even" : "odd")); html.startTag(HTMLWriter.TD); html.writeAttr("valign", "top"); html.write(entry.getKey()); html.endTag(HTMLWriter.TD); html.newLine(); html.startTag(HTMLWriter.TD); html.writeAttr(HTMLWriter.ALIGN, "top"); String sep = ""; for (Example e: entry.getValue()) { html.write(sep); html.writeLink('#' + e.getName(), e.getName()); sep = ", "; } html.endTag(HTMLWriter.TD); html.endTag(HTMLWriter.TR); html.newLine(); } html.endTag(HTMLWriter.TABLE); } @Override void startExample(Example e) throws IOException { String name = e.getName(); String initial = name.substring(0, 1).toUpperCase(); if (!initial.equals(currInitial)) { html.writeLinkDestination(initial, ""); currInitial = initial; } html.writeLinkDestination(name, ""); html.startTag(EXAMPLE_HEADER); html.write(e.getName()); html.endTag(EXAMPLE_HEADER); } @Override void showFile(Example e, File f) throws IOException { String text; try { text = read(f); } catch (IOException ex) { text = "Error reading " + f + ": " + ex; } if (!f.equals(e.file)) { html.startTag(FILE_HEADER); html.write(e.file.toURI().relativize(f.toURI()).toString()); html.endTag(FILE_HEADER); } html.startTag(HTMLWriter.DIV); html.writeAttr(CLASS, FILE); String legalHeader; Matcher m1 = copyrightHeaderPat.matcher(text); if (m1.matches()) { legalHeader = m1.group(1); text = m1.group(2); } else legalHeader = null; String infoHeader; Matcher m2 = infoHeaderPat.matcher(text); if (m2.matches()) { infoHeader = m2.group(1); text = m2.group(2); } else infoHeader = null; String legalId = null, infoId = null; if (legalHeader != null || infoHeader != null) { String sep = ""; html.startTag(HTMLWriter.SPAN); html.writeStyleAttr("float: right"); if (legalHeader != null) { legalId = nextId(); html.startTag(HTMLWriter.A); html.writeAttr(HTMLWriter.HREF, "javascript:unhide('" + legalId + "');"); //html.writeEntity("©"); html.write("Copyright"); html.endTag(HTMLWriter.A); sep = ", "; } if (infoHeader != null) { html.write(sep); infoId = nextId(); html.startTag(HTMLWriter.A); html.writeAttr(HTMLWriter.HREF, "javascript:unhide('" + infoId + "');"); html.write("Info"); html.endTag(HTMLWriter.A); sep = ", "; } html.endTag(HTMLWriter.SPAN); } html.startTag(HTMLWriter.P); html.writeAttr(CLASS, FILE); if (legalHeader != null) { html.startTag(HTMLWriter.SPAN); html.writeAttr(HTMLWriter.CLASS, "hidden"); html.writeAttr(HTMLWriter.ID, legalId); html.write(legalHeader); html.newLine(); html.endTag(HTMLWriter.SPAN); } if (infoHeader != null) { html.startTag(HTMLWriter.SPAN); html.writeAttr(HTMLWriter.CLASS, "hidden"); html.writeAttr(HTMLWriter.ID, infoId); html.write(infoHeader); html.newLine(); html.endTag(HTMLWriter.SPAN); } html.write(text); html.endTag(HTMLWriter.P); html.endTag(HTMLWriter.DIV); } @Override void run(Example e) throws IOException { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.run(pw, raw, verbose); pw.flush(); // only show Output: header if also showing files if (showFiles) { html.startTag(OUTPUT_HEADER); html.write("Output:"); html.endTag(OUTPUT_HEADER); } html.startTag(HTMLWriter.DIV); html.writeAttr(CLASS, OUTPUT); html.startTag(HTMLWriter.P); html.writeAttr(CLASS, OUTPUT); String[] lines = sw.toString().split("\n"); for (String line: lines) { html.write(line); html.newLine(); } html.endTag(HTMLWriter.P); html.endTag(HTMLWriter.DIV); } String nextId() { return "id" + (nextId++); } File file; HTMLWriter html; int nextId; String currInitial = ""; static final String TITLE_HEADER = HTMLWriter.H3; static final String INDEX_HEADER = HTMLWriter.H4; static final String EXAMPLE_HEADER = HTMLWriter.H4; static final String FILE_HEADER = HTMLWriter.H5; static final String OUTPUT_HEADER = HTMLWriter.H5; static final String CLASS = "class"; static final String FILE = "file"; static final String OUTPUT = "output"; } }