jjg@1490: /* jjg@1490: * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. jjg@1490: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@1490: * jjg@1490: * This code is free software; you can redistribute it and/or modify it jjg@1490: * under the terms of the GNU General Public License version 2 only, as jjg@1490: * published by the Free Software Foundation. jjg@1490: * jjg@1490: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@1490: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@1490: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@1490: * version 2 for more details (a copy is included in the LICENSE file that jjg@1490: * accompanied this code). jjg@1490: * jjg@1490: * You should have received a copy of the GNU General Public License version jjg@1490: * 2 along with this work; if not, write to the Free Software Foundation, jjg@1490: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@1490: * jjg@1490: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jjg@1490: * or visit www.oracle.com if you need additional information or have any jjg@1490: * questions. jjg@1490: */ jjg@1490: jjg@1490: /* jjg@1490: * @test jjg@1558: * @bug 8004834 8007610 jjg@1490: * @summary Add doclint support into javadoc jjg@1490: */ jjg@1490: jjg@1490: import java.io.File; jjg@1490: import java.io.PrintWriter; jjg@1490: import java.io.StringWriter; jjg@1490: import java.net.URI; jjg@1490: import java.util.Arrays; jjg@1490: import java.util.Collections; jjg@1490: import java.util.EnumSet; jjg@1490: import java.util.List; jjg@1490: import java.util.Set; jjg@1490: import java.util.regex.Matcher; jjg@1490: import java.util.regex.Pattern; jjg@1490: jjg@1490: import javax.tools.Diagnostic; jjg@1490: import javax.tools.DocumentationTool; jjg@1490: import javax.tools.DocumentationTool.DocumentationTask; jjg@1490: import javax.tools.JavaFileObject; jjg@1490: import javax.tools.SimpleJavaFileObject; jjg@1490: import javax.tools.StandardJavaFileManager; jjg@1490: import javax.tools.StandardLocation; jjg@1490: import javax.tools.ToolProvider; jjg@1490: import static javax.tools.Diagnostic.Kind.*; jjg@1490: jjg@1490: import com.sun.tools.javac.main.Main; jjg@1490: jjg@1490: public class DocLintTest { jjg@1490: public static void main(String... args) throws Exception { jjg@1490: new DocLintTest().run(); jjg@1490: } jjg@1490: jjg@1490: DocumentationTool javadoc; jjg@1490: StandardJavaFileManager fm; jjg@1490: JavaFileObject file; jjg@1490: jjg@1490: final String code = jjg@1490: /* 01 */ "/** Class comment. */\n" + jjg@1490: /* 02 */ "public class Test {\n" + jjg@1490: /* 03 */ " /** Method comment. */\n" + jjg@1490: /* 04 */ " public void method() { }\n" + jjg@1490: /* 05 */ "\n" + jjg@1490: /* 06 */ " /** Syntax < error. */\n" + jjg@1490: /* 07 */ " private void syntaxError() { }\n" + jjg@1490: /* 08 */ "\n" + jjg@1490: /* 09 */ " /** @see DoesNotExist */\n" + jjg@1490: /* 10 */ " protected void referenceError() { }\n" + jjg@1490: /* 11 */ "\n" + jjg@1490: /* 12 */ " /** @return */\n" + jjg@1490: /* 13 */ " public int emptyReturn() { return 0; }\n" + jjg@1490: /* 14 */ "}\n"; jjg@1490: jjg@1490: private final String rawDiags = "-XDrawDiagnostics"; jjg@1490: jjg@1490: private enum Message { jjg@1490: // doclint messages jjg@1490: DL_ERR6(ERROR, "Test.java:6:16: compiler.err.proc.messager: malformed HTML"), jjg@1490: DL_ERR9(ERROR, "Test.java:9:14: compiler.err.proc.messager: reference not found"), jjg@1490: DL_WRN12(WARNING, "Test.java:12:9: compiler.warn.proc.messager: no description for @return"), jjg@1490: jjg@1490: // doclint messages when -XDrawDiagnostics is not in effect jjg@1490: DL_ERR9A(ERROR, "Test.java:9: error: reference not found"), jjg@1490: DL_WRN12A(WARNING, "Test.java:12: warning: no description for @return"), jjg@1490: jjg@1490: // javadoc messages about bad content: these should only appear when doclint is disabled jjg@1490: JD_WRN10(WARNING, "Test.java:10: warning - Tag @see: reference not found: DoesNotExist"), jjg@1490: JD_WRN13(WARNING, "Test.java:13: warning - @return tag has no arguments."), jjg@1490: jjg@1490: // javadoc messages for bad options jjg@1490: OPT_BADARG(ERROR, "javadoc: error - Invalid argument for -Xdoclint option"), jjg@1490: OPT_BADQUAL(ERROR, "javadoc: error - Access qualifiers not permitted for -Xdoclint arguments"); jjg@1490: jjg@1490: final Diagnostic.Kind kind; jjg@1490: final String text; jjg@1490: jjg@1490: static Message get(String text) { jjg@1490: for (Message m: values()) { jjg@1490: if (m.text.equals(text)) jjg@1490: return m; jjg@1490: } jjg@1490: return null; jjg@1490: } jjg@1490: jjg@1490: Message(Diagnostic.Kind kind, String text) { jjg@1490: this.kind = kind; jjg@1490: this.text = text; jjg@1490: } jjg@1490: jjg@1490: @Override jjg@1490: public String toString() { jjg@1490: return "[" + kind + ",\"" + text + "\"]"; jjg@1490: } jjg@1490: } jjg@1490: jjg@1490: void run() throws Exception { jjg@1490: javadoc = ToolProvider.getSystemDocumentationTool(); jjg@1490: fm = javadoc.getStandardFileManager(null, null, null); jjg@1490: fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File("."))); jjg@1490: file = new SimpleJavaFileObject(URI.create("Test.java"), JavaFileObject.Kind.SOURCE) { jjg@1490: @Override jjg@1490: public CharSequence getCharContent(boolean ignoreEncoding) { jjg@1490: return code; jjg@1490: } jjg@1490: }; jjg@1490: jjg@1490: test(Collections.emptyList(), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.DL_ERR9A, Message.DL_WRN12A)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.DL_ERR9, Message.DL_WRN12)); jjg@1490: jjg@1490: test(Arrays.asList("-Xdoclint:none"), jjg@1490: Main.Result.OK, jjg@1490: EnumSet.of(Message.JD_WRN10, Message.JD_WRN13)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint"), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.DL_ERR9, Message.DL_WRN12)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:all/public"), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.OPT_BADQUAL)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:all", "-public"), jjg@1490: Main.Result.OK, jjg@1490: EnumSet.of(Message.DL_WRN12)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:syntax"), jjg@1490: Main.Result.OK, jjg@1490: EnumSet.of(Message.DL_WRN12)); jjg@1490: jjg@1558: test(Arrays.asList(rawDiags, "-private"), jjg@1558: Main.Result.ERROR, jjg@1558: EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12)); jjg@1558: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:syntax", "-private"), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.DL_ERR6, Message.DL_WRN12)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:reference"), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.DL_ERR9)); jjg@1490: jjg@1490: test(Arrays.asList(rawDiags, "-Xdoclint:badarg"), jjg@1490: Main.Result.ERROR, jjg@1490: EnumSet.of(Message.OPT_BADARG)); jjg@1490: jjg@1490: if (errors > 0) jjg@1490: throw new Exception(errors + " errors occurred"); jjg@1490: } jjg@1490: jjg@1490: void test(List opts, Main.Result expectResult, Set expectMessages) { jjg@1490: System.err.println("test: " + opts); jjg@1490: StringWriter sw = new StringWriter(); jjg@1490: PrintWriter pw = new PrintWriter(sw); jjg@1490: List files = Arrays.asList(file); jjg@1490: try { jjg@1490: DocumentationTask t = javadoc.getTask(pw, fm, null, null, opts, files); jjg@1490: boolean ok = t.call(); jjg@1490: pw.close(); jjg@1490: String out = sw.toString().replaceAll("[\r\n]+", "\n"); jjg@1490: if (!out.isEmpty()) jjg@1490: System.err.println(out); jjg@1490: if (ok && expectResult != Main.Result.OK) { jjg@1490: error("Compilation succeeded unexpectedly"); jjg@1490: } else if (!ok && expectResult != Main.Result.ERROR) { jjg@1490: error("Compilation failed unexpectedly"); jjg@1490: } else jjg@1490: check(out, expectMessages); jjg@1490: } catch (IllegalArgumentException e) { jjg@1490: System.err.println(e); jjg@1490: String expectOut = expectMessages.iterator().next().text; jjg@1490: if (expectResult != Main.Result.CMDERR) jjg@1490: error("unexpected exception caught"); jjg@1490: else if (!e.getMessage().equals(expectOut)) { jjg@1490: error("unexpected exception message: " jjg@1490: + e.getMessage() jjg@1490: + " expected: " + expectOut); jjg@1490: } jjg@1490: } jjg@1490: jjg@1490: // if (errors > 0) jjg@1490: // throw new Error("stop"); jjg@1490: } jjg@1490: jjg@1490: private void check(String out, Set expect) { jjg@1490: Pattern ignore = Pattern.compile("^(Building|Constructing|Generating|Loading|Standard|Starting| ) .*"); jjg@1490: Pattern stats = Pattern.compile("^([1-9]+) (error|warning)(s?)"); jjg@1490: Set found = EnumSet.noneOf(Message.class); jjg@1490: int e = 0, w = 0; jjg@1490: for (String line: out.split("[\r\n]+")) { jjg@1490: if (ignore.matcher(line).matches()) jjg@1490: continue; jjg@1490: jjg@1490: Matcher s = stats.matcher(line); jjg@1490: if (s.matches()) { jjg@1490: int i = Integer.valueOf(s.group(1)); jjg@1490: if (s.group(2).equals("error")) jjg@1490: e++; jjg@1490: else jjg@1490: w++; jjg@1490: continue; jjg@1490: } jjg@1490: jjg@1490: Message m = Message.get(line); jjg@1490: if (m == null) jjg@1490: error("Unexpected line: " + line); jjg@1490: else jjg@1490: found.add(m); jjg@1490: } jjg@1490: for (Message m: expect) { jjg@1490: if (!found.contains(m)) jjg@1490: error("expected message not found: " + m.text); jjg@1490: } jjg@1490: for (Message m: found) { jjg@1490: if (!expect.contains(m)) jjg@1490: error("unexpected message found: " + m.text); jjg@1490: } jjg@1490: } jjg@1490: jjg@1490: void error(String msg) { jjg@1490: System.err.println("Error: " + msg); jjg@1490: errors++; jjg@1490: } jjg@1490: jjg@1490: int errors; jjg@1490: }