mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8154482: javadoc tool must support legacy doclet and taglet
Reviewed-by: jjg
This commit is contained in:
parent
9290ce0c7b
commit
4be9fb29fa
9 changed files with 564 additions and 131 deletions
|
@ -1,4 +1,4 @@
|
|||
doclet.build_version=Standard Doclet version {0}
|
||||
doclet.build_version=Standard Doclet (Old) version {0}
|
||||
doclet.Contents=Contents
|
||||
doclet.Overview=Overview
|
||||
doclet.Window_Overview=Overview List
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
doclet.build_version=Standard Doclet (Next) version {0}
|
||||
doclet.build_version=Standard Doclet version {0}
|
||||
doclet.Contents=Contents
|
||||
doclet.Overview=Overview
|
||||
doclet.Window_Overview=Overview List
|
||||
|
|
|
@ -550,7 +550,7 @@ public class DocEnv {
|
|||
// Messager should be replaced by a more general
|
||||
// compilation environment. This can probably
|
||||
// subsume DocEnv as well.
|
||||
messager.exit();
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -59,13 +59,6 @@ public class Main {
|
|||
* @return The return code.
|
||||
*/
|
||||
public static int execute(String... args) {
|
||||
// NOTE: the following should be removed when the old doclet
|
||||
// is removed.
|
||||
if (args != null && args.length > 0 && "-Xold".equals(args[0])) {
|
||||
String[] nargs = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, nargs, 0, nargs.length);
|
||||
return com.sun.tools.javadoc.Main.execute(nargs);
|
||||
}
|
||||
Start jdoc = new Start();
|
||||
return jdoc.begin(args);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
|
@ -139,7 +139,7 @@ public class Messager extends Log implements Reporter {
|
|||
}
|
||||
}
|
||||
|
||||
public class ExitJavadoc extends Error {
|
||||
public static class ExitJavadoc extends Error {
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
|
@ -416,15 +416,6 @@ public class Messager extends Log implements Reporter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force program exit, e.g., from a fatal error.
|
||||
* <p>
|
||||
* TODO: This method does not really belong here.
|
||||
*/
|
||||
public void exit() {
|
||||
throw new ExitJavadoc();
|
||||
}
|
||||
|
||||
private void report(DiagnosticType type, String pos, String msg) {
|
||||
switch (type) {
|
||||
case ERROR:
|
||||
|
|
|
@ -66,6 +66,7 @@ import jdk.javadoc.doclet.Doclet.Option;
|
|||
import jdk.javadoc.doclet.DocletEnvironment;
|
||||
|
||||
import static com.sun.tools.javac.main.Option.*;
|
||||
|
||||
/**
|
||||
* Main program of Javadoc.
|
||||
* Previously named "Main".
|
||||
|
@ -79,6 +80,12 @@ import static com.sun.tools.javac.main.Option.*;
|
|||
* @author Neal Gafter (rewrite)
|
||||
*/
|
||||
public class Start extends ToolOption.Helper {
|
||||
|
||||
private static final Class<?> OldStdDoclet =
|
||||
com.sun.tools.doclets.standard.Standard.class;
|
||||
|
||||
private static final Class<?> StdDoclet =
|
||||
jdk.javadoc.internal.doclets.standard.Standard.class;
|
||||
/** Context for this invocation. */
|
||||
private final Context context;
|
||||
|
||||
|
@ -193,18 +200,26 @@ public class Start extends ToolOption.Helper {
|
|||
if (foot != null)
|
||||
messager.notice(foot);
|
||||
|
||||
if (exit) exit();
|
||||
if (exit)
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit
|
||||
*/
|
||||
private void exit() {
|
||||
messager.exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main program - external wrapper
|
||||
* Main program - external wrapper. In order to maintain backward
|
||||
* CLI compatibility, we dispatch to the old tool or the old doclet's
|
||||
* Start mechanism, based on the options present on the command line
|
||||
* with the following precedence:
|
||||
* 1. presence of -Xold, dispatch to old tool
|
||||
* 2. doclet variant, if old, dispatch to old Start
|
||||
* 3. taglet variant, if old, dispatch to old Start
|
||||
*
|
||||
* Thus the presence of -Xold switches the tool, soon after command files
|
||||
* if any, are expanded, this is performed here, noting that the messager
|
||||
* is available at this point in time.
|
||||
* The doclet/taglet tests are performed in the begin method, further on,
|
||||
* this is to minimize argument processing and most importantly the impact
|
||||
* of class loader creation, needed to detect the doclet/taglet class variants.
|
||||
*/
|
||||
int begin(String... argv) {
|
||||
// Preprocess @file arguments
|
||||
|
@ -212,14 +227,18 @@ public class Start extends ToolOption.Helper {
|
|||
argv = CommandLine.parse(argv);
|
||||
} catch (FileNotFoundException e) {
|
||||
messager.error("main.cant.read", e.getMessage());
|
||||
exit();
|
||||
throw new Messager.ExitJavadoc();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
exit();
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
|
||||
List<String> argList = Arrays.asList(argv);
|
||||
boolean ok = begin(argList, Collections.<JavaFileObject> emptySet());
|
||||
if (argv.length > 0 && "-Xold".equals(argv[0])) {
|
||||
messager.warning("main.legacy_api");
|
||||
String[] nargv = Arrays.copyOfRange(argv, 1, argv.length);
|
||||
return com.sun.tools.javadoc.Main.execute(nargv);
|
||||
}
|
||||
boolean ok = begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@ -231,11 +250,11 @@ public class Start extends ToolOption.Helper {
|
|||
List<String> opts = new ArrayList<>();
|
||||
for (String opt: options)
|
||||
opts.add(opt);
|
||||
|
||||
return begin(opts, fileObjects);
|
||||
}
|
||||
|
||||
private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
|
||||
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
if (fileManager == null) {
|
||||
JavacFileManager.preRegister(context);
|
||||
|
@ -244,9 +263,8 @@ public class Start extends ToolOption.Helper {
|
|||
((BaseFileManager) fileManager).autoClose = true;
|
||||
}
|
||||
}
|
||||
// locale and doclet needs to be determined first
|
||||
// locale, doclet and maybe taglet, needs to be determined first
|
||||
docletClass = preProcess(fileManager, options);
|
||||
|
||||
if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
|
||||
// no need to dispatch to old, safe to init now
|
||||
initMessager();
|
||||
|
@ -257,7 +275,7 @@ public class Start extends ToolOption.Helper {
|
|||
exc.printStackTrace();
|
||||
if (!apiMode) {
|
||||
error("main.could_not_instantiate_class", docletClass);
|
||||
messager.exit();
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
throw new ClientCodeException(exc);
|
||||
}
|
||||
|
@ -267,6 +285,7 @@ public class Start extends ToolOption.Helper {
|
|||
= new com.sun.tools.javadoc.Start(context);
|
||||
return ostart.begin(docletClass, options, fileObjects);
|
||||
}
|
||||
warn("main.legacy_api");
|
||||
String[] array = options.toArray(new String[options.size()]);
|
||||
return com.sun.tools.javadoc.Main.execute(array) == 0;
|
||||
}
|
||||
|
@ -459,6 +478,11 @@ public class Start extends ToolOption.Helper {
|
|||
String userDocletPath = null;
|
||||
String userDocletName = null;
|
||||
|
||||
// taglet specifying arguments, since tagletpath is a doclet
|
||||
// functionality, assume they are repeated and inspect all.
|
||||
List<File> userTagletPath = new ArrayList<>();
|
||||
List<String> userTagletNames = new ArrayList<>();
|
||||
|
||||
// Step 1: loop through the args, set locale early on, if found.
|
||||
for (int i = 0 ; i < argv.size() ; i++) {
|
||||
String arg = argv.get(i);
|
||||
|
@ -484,13 +508,20 @@ public class Start extends ToolOption.Helper {
|
|||
} else {
|
||||
userDocletPath += File.pathSeparator + argv.get(i);
|
||||
}
|
||||
} else if ("-taglet".equals(arg)) {
|
||||
userTagletNames.add(argv.get(i + 1));
|
||||
} else if ("-tagletpath".equals(arg)) {
|
||||
for (String pathname : argv.get(i + 1).split(File.pathSeparator)) {
|
||||
userTagletPath.add(new File(pathname));
|
||||
}
|
||||
}
|
||||
// Step 2: a doclet has already been provided,
|
||||
// nothing more to do.
|
||||
}
|
||||
|
||||
// Step 2: a doclet is provided, nothing more to do.
|
||||
if (docletClass != null) {
|
||||
return docletClass;
|
||||
}
|
||||
|
||||
// Step 3: doclet name specified ? if so find a ClassLoader,
|
||||
// and load it.
|
||||
if (userDocletName != null) {
|
||||
|
@ -506,38 +537,80 @@ public class Start extends ToolOption.Helper {
|
|||
try {
|
||||
((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
|
||||
} catch (IOException ioe) {
|
||||
panic("main.doclet_no_classloader_found", ioe);
|
||||
return null; // keep compiler happy
|
||||
error("main.doclet_could_not_set_location", paths);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
}
|
||||
cl = fileManager.getClassLoader(DOCLET_PATH);
|
||||
if (cl == null) {
|
||||
// despite doclet specified on cmdline no classloader found!
|
||||
panic("main.doclet_no_classloader_found", userDocletName);
|
||||
return null; // keep compiler happy
|
||||
error("main.doclet_no_classloader_found", userDocletName);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
}
|
||||
try {
|
||||
Class<?> klass = cl.loadClass(userDocletName);
|
||||
ensureReadable(klass);
|
||||
return klass;
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
panic("main.doclet_class_not_found", userDocletName);
|
||||
return null; // keep compiler happy
|
||||
error("main.doclet_class_not_found", userDocletName);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Step 4: we have a doclet, try loading it, otherwise
|
||||
// return back the standard doclet
|
||||
|
||||
// Step 4: we have a doclet, try loading it
|
||||
if (docletName != null) {
|
||||
try {
|
||||
return Class.forName(docletName, true, getClass().getClassLoader());
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
panic("main.doclet_class_not_found", userDocletName);
|
||||
return null; // happy compiler, should not happen
|
||||
error("main.doclet_class_not_found", userDocletName);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
} else {
|
||||
return jdk.javadoc.internal.doclets.standard.Standard.class;
|
||||
}
|
||||
|
||||
// Step 5: we don't have a doclet specified, do we have taglets ?
|
||||
if (!userTagletNames.isEmpty() && hasOldTaglet(userTagletNames, userTagletPath)) {
|
||||
// found a bogey, return the old doclet
|
||||
return OldStdDoclet;
|
||||
}
|
||||
|
||||
// finally
|
||||
return StdDoclet;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method returns true iff it finds a legacy taglet, but for
|
||||
* all other conditions including errors it returns false, allowing
|
||||
* nature to take its own course.
|
||||
*/
|
||||
private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) {
|
||||
if (!fileManager.hasLocation(TAGLET_PATH)) {
|
||||
try {
|
||||
((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths);
|
||||
} catch (IOException ioe) {
|
||||
error("main.doclet_could_not_set_location", tagletPaths);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
}
|
||||
ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH);
|
||||
if (cl == null) {
|
||||
// no classloader found!
|
||||
error("main.doclet_no_classloader_found", tagletNames.get(0));
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
for (String tagletName : tagletNames) {
|
||||
try {
|
||||
Class<?> klass = cl.loadClass(tagletName);
|
||||
ensureReadable(klass);
|
||||
if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) {
|
||||
return true;
|
||||
}
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
error("main.doclet_class_not_found", tagletName);
|
||||
throw new Messager.ExitJavadoc();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void parseArgs(List<String> args, List<String> javaNames) {
|
||||
|
@ -595,16 +668,14 @@ public class Start extends ToolOption.Helper {
|
|||
usage(true);
|
||||
}
|
||||
|
||||
// a terminal call, will not return
|
||||
void panic(String key, Object... args) {
|
||||
error(key, args);
|
||||
messager.exit();
|
||||
}
|
||||
|
||||
void error(String key, Object... args) {
|
||||
messager.error(key, args);
|
||||
}
|
||||
|
||||
void warn(String key, Object... args) {
|
||||
messager.warning(key, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate an option with no arguments was given.
|
||||
*/
|
||||
|
|
|
@ -73,7 +73,8 @@ main.Xusage=\
|
|||
\ given module. <other-module> may be ALL-UNNAMED to require\n\
|
||||
\ the unnamed module.\n\
|
||||
\ -Xmodule:<module-name> Specify a module to which the classes being compiled belong.\n\
|
||||
\ -Xpatch:<path> Specify location of module class files to patch\n
|
||||
\ -Xpatch:<path> Specify location of module class files to patch\n\
|
||||
\ -Xold Invoke the legacy javadoc tool\n
|
||||
|
||||
main.Xusage.foot=\
|
||||
These options are non-standard and subject to change without notice.
|
||||
|
@ -96,6 +97,7 @@ For example, on the JDK Classic or HotSpot VMs, add the option -J-Xmx\n\
|
|||
such as -J-Xmx32m.
|
||||
main.done_in=[done in {0} ms]
|
||||
main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}).
|
||||
main.doclet_could_not_set_location=Could not set location for {0}
|
||||
main.doclet_no_classloader_found=Could not obtain classloader to load {0}
|
||||
main.could_not_instantiate_class=Could not instantiate class {0}
|
||||
main.doclet_class_not_found=Cannot find doclet class {0}
|
||||
|
@ -109,10 +111,15 @@ main.release.bootclasspath.conflict=option {0} cannot be used together with -rel
|
|||
main.unsupported.release.version=release version {0} not supported
|
||||
main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager.
|
||||
main.unknown.error=an unknown error has occurred
|
||||
main.legacy_api=The old Doclet and Taglet APIs in the packages\n\
|
||||
com.sun.javadoc, com.sun.tools.doclets and their implementations\n\
|
||||
are planned to be removed in a future JDK release. These\n\
|
||||
components have been superseded by the new APIs in jdk.javadoc.doclet.\n\
|
||||
Users are strongly recommended to migrate to the new APIs.\n
|
||||
|
||||
javadoc.class_not_found=Class {0} not found.
|
||||
javadoc.error=error
|
||||
javadoc.warning=warning
|
||||
|
||||
javadoc.error.msg={0}: error - {1}
|
||||
javadoc.warning.msg={0}: warning - {1}
|
||||
javadoc.note.msg = {1}
|
||||
|
|
|
@ -23,96 +23,349 @@
|
|||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035473
|
||||
* @summary make sure the new doclet is invoked by default, and -Xold
|
||||
* @bug 8035473 8154482
|
||||
* @summary make sure the javadoc tool responds correctly to Xold,
|
||||
* old doclets and taglets.
|
||||
* @library /tools/lib
|
||||
* @build toolbox.ToolBox toolbox.TestRunner
|
||||
* @run main EnsureNewOldDoclet
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.sun.javadoc.Tag;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
|
||||
import toolbox.*;
|
||||
|
||||
|
||||
/**
|
||||
* Dummy javadoc comment.
|
||||
* This test ensures the doclet responds correctly when given
|
||||
* various conditions that force a fall back to the old javadoc
|
||||
* tool. The following condition in the order described will
|
||||
* force a dispatch to the old tool, -Xold, old doclet and old taglet.
|
||||
*
|
||||
*/
|
||||
public class EnsureNewOldDoclet {
|
||||
public class EnsureNewOldDoclet extends TestRunner {
|
||||
|
||||
final File javadoc;
|
||||
final ToolBox tb;
|
||||
final File testSrc;
|
||||
final String thisClassName;
|
||||
final Path javadocPath;
|
||||
final ExecTask task;
|
||||
final String testClasses;
|
||||
final PrintStream ostream;
|
||||
|
||||
final static Pattern Expected1 = Pattern.compile("^Standard Doclet \\(Next\\) version.*");
|
||||
final static Pattern Expected2 = Pattern.compile("^Standard Doclet version.*");
|
||||
final static String CLASS_NAME = "EnsureNewOldDoclet";
|
||||
final static String OLD_DOCLET_CLASS_NAME = CLASS_NAME + "$OldDoclet";
|
||||
final static String NEW_DOCLET_CLASS_NAME = CLASS_NAME + "$NewDoclet"; //unused
|
||||
final static String OLD_TAGLET_CLASS_NAME = CLASS_NAME + "$OldTaglet";
|
||||
final static String NEW_TAGLET_CLASS_NAME = CLASS_NAME + "$NewTaglet";
|
||||
|
||||
public EnsureNewOldDoclet() {
|
||||
File javaHome = new File(System.getProperty("java.home"));
|
||||
if (javaHome.getName().endsWith("jre"))
|
||||
javaHome = javaHome.getParentFile();
|
||||
javadoc = new File(new File(javaHome, "bin"), "javadoc");
|
||||
testSrc = new File(System.getProperty("test.src"));
|
||||
thisClassName = EnsureNewOldDoclet.class.getName();
|
||||
final static Pattern OLD_HEADER = Pattern.compile("^Standard Doclet \\(Old\\) version.*");
|
||||
final static Pattern NEW_HEADER = Pattern.compile("^Standard Doclet version.*");
|
||||
|
||||
|
||||
final static String OLD_DOCLET_MARKER = "OLD_DOCLET_MARKER";
|
||||
final static String OLD_TAGLET_MARKER = "Registered: OldTaglet";
|
||||
|
||||
final static String NEW_DOCLET_MARKER = "NEW_DOCLET_MARKER";
|
||||
final static String NEW_TAGLET_MARKER = "Registered Taglet " + CLASS_NAME + "\\$NewTaglet";
|
||||
|
||||
final static Pattern WARN_TEXT = Pattern.compile("Users are strongly recommended to migrate" +
|
||||
" to the new APIs.");
|
||||
final static String OLD_DOCLET_ERROR = "java.lang.NoSuchMethodException: " +
|
||||
CLASS_NAME +"\\$NewTaglet";
|
||||
final static Pattern NEW_DOCLET_ERROR = Pattern.compile(".*java.lang.ClassCastException.*Taglet " +
|
||||
CLASS_NAME + "\\$OldTaglet.*");
|
||||
|
||||
final static String OLD_STDDOCLET = "com.sun.tools.doclets.standard.Standard";
|
||||
final static String NEW_STDDOCLET = "jdk.javadoc.internal.doclets.standard.Standard";
|
||||
|
||||
|
||||
public EnsureNewOldDoclet() throws Exception {
|
||||
super(System.err);
|
||||
ostream = System.err;
|
||||
testClasses = System.getProperty("test.classes");
|
||||
tb = new ToolBox();
|
||||
javadocPath = tb.getJDKTool("javadoc");
|
||||
task = new ExecTask(tb, javadocPath);
|
||||
testSrc = new File("Foo.java");
|
||||
generateSample(testSrc);
|
||||
}
|
||||
|
||||
void generateSample(File testSrc) throws Exception {
|
||||
String nl = System.getProperty("line.separator");
|
||||
String src = Arrays.asList(
|
||||
"/**",
|
||||
" * A test class to test javadoc. Nothing more nothing less.",
|
||||
" */",
|
||||
" public class Foo{}").stream().collect(Collectors.joining(nl));
|
||||
tb.writeFile(testSrc.getPath(), src);
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
EnsureNewOldDoclet test = new EnsureNewOldDoclet();
|
||||
test.run1();
|
||||
test.run2();
|
||||
new EnsureNewOldDoclet().runTests();
|
||||
}
|
||||
|
||||
// make sure new doclet is invoked by default
|
||||
void run1() throws Exception {
|
||||
List<String> output = doTest(javadoc.getPath(),
|
||||
"-classpath", ".", // insulates us from ambient classpath
|
||||
"-Xdoclint:none",
|
||||
"-package",
|
||||
new File(testSrc, thisClassName + ".java").getPath());
|
||||
System.out.println(output);
|
||||
for (String x : output) {
|
||||
if (Expected1.matcher(x).matches()) {
|
||||
// input: nothing, default mode
|
||||
// outcome: new tool and new doclet
|
||||
@Test
|
||||
public void testDefault() throws Exception {
|
||||
setArgs("-classpath", ".", // insulates us from ambient classpath
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
checkOutput(testName, out, NEW_HEADER);
|
||||
}
|
||||
|
||||
// input: -Xold
|
||||
// outcome: old tool
|
||||
@Test
|
||||
public void testXold() throws Exception {
|
||||
setArgs("-Xold",
|
||||
"-classpath", ".", // ambient classpath insulation
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, OLD_HEADER);
|
||||
checkOutput(testName, err, WARN_TEXT);
|
||||
}
|
||||
|
||||
// input: old doclet
|
||||
// outcome: old tool
|
||||
@Test
|
||||
public void testOldDoclet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-doclet",
|
||||
OLD_DOCLET_CLASS_NAME,
|
||||
"-docletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, OLD_DOCLET_MARKER);
|
||||
checkOutput(testName, err, WARN_TEXT);
|
||||
}
|
||||
|
||||
// input: old taglet
|
||||
// outcome: old tool
|
||||
@Test
|
||||
public void testOldTaglet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-taglet",
|
||||
OLD_TAGLET_CLASS_NAME,
|
||||
"-tagletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, OLD_TAGLET_MARKER);
|
||||
checkOutput(testName, err, WARN_TEXT);
|
||||
}
|
||||
|
||||
// input: new doclet and old taglet
|
||||
// outcome: new doclet with failure
|
||||
@Test
|
||||
public void testNewDocletOldTaglet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-doclet",
|
||||
NEW_STDDOCLET,
|
||||
"-taglet",
|
||||
OLD_TAGLET_CLASS_NAME,
|
||||
"-tagletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.FAIL, 1);
|
||||
//Task.Result tr = task.run();
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, NEW_HEADER);
|
||||
checkOutput(testName, err, NEW_DOCLET_ERROR);
|
||||
}
|
||||
|
||||
// input: old doclet and old taglet
|
||||
// outcome: old doclet and old taglet should register
|
||||
@Test
|
||||
public void testOldDocletOldTaglet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-doclet",
|
||||
OLD_STDDOCLET,
|
||||
"-taglet",
|
||||
OLD_TAGLET_CLASS_NAME,
|
||||
"-tagletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, OLD_HEADER);
|
||||
checkOutput(testName, out, OLD_TAGLET_MARKER);
|
||||
checkOutput(testName, err, WARN_TEXT);
|
||||
}
|
||||
|
||||
// input: new doclet and new taglet
|
||||
// outcome: new doclet and new taglet should register
|
||||
@Test
|
||||
public void testNewDocletNewTaglet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-doclet",
|
||||
NEW_STDDOCLET,
|
||||
"-taglet",
|
||||
NEW_TAGLET_CLASS_NAME,
|
||||
"-tagletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, NEW_HEADER);
|
||||
checkOutput(testName, out, NEW_TAGLET_MARKER);
|
||||
}
|
||||
|
||||
// input: old doclet and new taglet
|
||||
// outcome: old doclet and error
|
||||
@Test
|
||||
public void testOldDocletNewTaglet() throws Exception {
|
||||
setArgs("-classpath", ".", // ambient classpath insulation
|
||||
"-doclet",
|
||||
OLD_STDDOCLET,
|
||||
"-taglet",
|
||||
NEW_TAGLET_CLASS_NAME,
|
||||
"-tagletpath",
|
||||
testClasses,
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.FAIL, 1);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, OLD_HEADER);
|
||||
checkOutput(testName, err, WARN_TEXT);
|
||||
checkOutput(testName, err, OLD_DOCLET_ERROR);
|
||||
}
|
||||
|
||||
void setArgs(String... args) {
|
||||
ostream.println("cmds: " + Arrays.asList(args));
|
||||
task.args(args);
|
||||
}
|
||||
|
||||
void checkOutput(String testCase, List<String> content, String toFind) throws Exception {
|
||||
checkOutput(testCase, content, Pattern.compile(".*" + toFind + ".*"));
|
||||
}
|
||||
|
||||
void checkOutput(String testCase, List<String> content, Pattern toFind) throws Exception {
|
||||
ostream.println("---" + testCase + "---");
|
||||
content.stream().forEach(x -> System.out.println(x));
|
||||
for (String x : content) {
|
||||
ostream.println(x);
|
||||
if (toFind.matcher(x).matches()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Exception("run1: Expected string not found:");
|
||||
throw new Exception(testCase + ": Expected string not found: " + toFind);
|
||||
}
|
||||
|
||||
// make sure the old doclet is invoked with -Xold
|
||||
void run2() throws Exception {
|
||||
List<String> output = doTest(javadoc.getPath(),
|
||||
"-Xold",
|
||||
"-classpath", ".", // insulates us from ambient classpath
|
||||
"-Xdoclint:none",
|
||||
"-package",
|
||||
new File(testSrc, thisClassName + ".java").getPath());
|
||||
|
||||
for (String x : output) {
|
||||
if (Expected2.matcher(x).matches()) {
|
||||
throw new Exception("run2: Expected string not found");
|
||||
}
|
||||
return;
|
||||
public static class OldDoclet extends com.sun.javadoc.Doclet {
|
||||
public static boolean start(com.sun.javadoc.RootDoc root) {
|
||||
System.out.println(OLD_DOCLET_MARKER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* More dummy comments.
|
||||
*/
|
||||
List<String> doTest(String... args) throws Exception {
|
||||
List<String> output = new ArrayList<>();
|
||||
// run javadoc in separate process to ensure doclet executed under
|
||||
// normal user conditions w.r.t. classloader
|
||||
Process p = new ProcessBuilder()
|
||||
.command(args)
|
||||
.redirectErrorStream(true)
|
||||
.start();
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
|
||||
String line = in.readLine();
|
||||
while (line != null) {
|
||||
output.add(line.trim());
|
||||
line = in.readLine();
|
||||
public static class OldTaglet implements com.sun.tools.doclets.Taglet {
|
||||
|
||||
public static void register(Map map) {
|
||||
EnsureNewOldDoclet.OldTaglet tag = new OldTaglet();
|
||||
com.sun.tools.doclets.Taglet t = (com.sun.tools.doclets.Taglet) map.get(tag.getName());
|
||||
System.out.println(OLD_TAGLET_MARKER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inField() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inConstructor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inOverview() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inPackage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInlineTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "OldTaglet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Tag tag) {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Tag[] tags) {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
int rc = p.waitFor();
|
||||
if (rc != 0)
|
||||
throw new Exception("javadoc failed, rc:" + rc);
|
||||
return output;
|
||||
|
||||
public static class NewTaglet implements jdk.javadoc.doclet.taglet.Taglet {
|
||||
|
||||
@Override
|
||||
public Set<Location> getAllowedLocations() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInlineTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NewTaglet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(DocTree tag) {
|
||||
return tag.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(List<? extends DocTree> tags) {
|
||||
return tags.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
118
langtools/test/tools/lib/toolbox/TestRunner.java
Normal file
118
langtools/test/tools/lib/toolbox/TestRunner.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
package toolbox;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Utility class to manage and execute sub-tests within a test.
|
||||
*
|
||||
* This class does the following:
|
||||
* i. invokes those test methods annotated with @Test
|
||||
* ii. keeps track of successful and failed tests
|
||||
* iii. throws an Exception if any test fails.
|
||||
* iv. provides a test summary at the end of the run.
|
||||
*
|
||||
* Tests must extend this class, annotate the test methods
|
||||
* with @Test and call one of the runTests method.
|
||||
*/
|
||||
|
||||
public abstract class TestRunner {
|
||||
/** Marker annotation for test cases. */
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Test { }
|
||||
|
||||
int testCount = 0;
|
||||
int errorCount = 0;
|
||||
|
||||
public String testName = null;
|
||||
|
||||
final PrintStream out;
|
||||
|
||||
/**
|
||||
* Constructs the Object.
|
||||
* @param out the PrintStream to print output to.
|
||||
*/
|
||||
public TestRunner(PrintStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all methods annotated with @Test.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public void runTests() throws Exception {
|
||||
runTests(f -> new Object[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all methods annotated with @Test.
|
||||
* @param f a lambda expression to specify arguments.
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public void runTests(Function<Method, Object[]> f) throws Exception {
|
||||
for (Method m : getClass().getDeclaredMethods()) {
|
||||
Annotation a = m.getAnnotation(Test.class);
|
||||
if (a != null) {
|
||||
testName = m.getName();
|
||||
try {
|
||||
testCount++;
|
||||
out.println("test: " + testName);
|
||||
m.invoke(this, f.apply(m));
|
||||
} catch (InvocationTargetException e) {
|
||||
errorCount++;
|
||||
Throwable cause = e.getCause();
|
||||
out.println("Exception: " + e.getCause());
|
||||
cause.printStackTrace(out);
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
if (testCount == 0) {
|
||||
throw new Error("no tests found");
|
||||
}
|
||||
|
||||
StringBuilder summary = new StringBuilder();
|
||||
if (testCount != 1) {
|
||||
summary.append(testCount).append(" tests");
|
||||
}
|
||||
if (errorCount > 0) {
|
||||
if (summary.length() > 0) {
|
||||
summary.append(", ");
|
||||
}
|
||||
summary.append(errorCount).append(" errors");
|
||||
}
|
||||
out.println(summary);
|
||||
if (errorCount > 0) {
|
||||
throw new Exception(errorCount + " errors found");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue