1 /*
2  * Copyright (c) 2003, 2008, 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  * A utility used to invoke and test the javadoc tool.
26  *
27  * @author Scott Seligman
28  */
29 
30 
31 import java.io.*;
32 import java.util.*;
33 import com.sun.javadoc.*;
34 
35 
36 public class Tester {
37 
38     protected final String TEST_SRC = System.getProperty("test.src", ".");
39     protected final String TEST_CLASSES = System.getProperty("test.classes",
40                                                              ".");
41     private final String DEFAULT_ARGS[] = {
42         "-sourcepath", TEST_SRC,
43     };
44 
45     private final File outputFile = new File(TEST_CLASSES, "testrun.out");
46     private final File expectedOutputFile = new File(TEST_SRC, "expected.out");
47 //  private final File bootstrapMarkerFile = new File("bootstrap");
48 
49     // True if we should "set expectations" by writing the expected output file
50     // rather than reading it and comparing.
51 //  private final boolean bootstrap = bootstrapMarkerFile.isFile();
52 
53     private String docletName;
54     private String[] args;
55     private Writer out = null;
56 
57 
58     /*
59      * Individual tests can extend this to create generics-aware doclets.
60      */
61     public static abstract class Doclet extends com.sun.javadoc.Doclet {
languageVersion()62         public static LanguageVersion languageVersion() {
63             return LanguageVersion.JAVA_1_5;
64         }
65     }
66 
67 
Tester(String docletName)68     public Tester(String docletName) {
69         this(docletName, new String[0]);
70     }
71 
Tester(String docletName, String... additionalArgs)72     public Tester(String docletName, String... additionalArgs) {
73         this.docletName = docletName;
74 
75         int len = DEFAULT_ARGS.length + additionalArgs.length;
76         args = new String[len];
77         System.arraycopy(DEFAULT_ARGS, 0, args, 0, DEFAULT_ARGS.length);
78         System.arraycopy(additionalArgs, 0, args, DEFAULT_ARGS.length,
79                          additionalArgs.length);
80 
81         try {
82             out = new BufferedWriter(new FileWriter(outputFile));
83         } catch (IOException e) {
84             throw new Error("Could not open output file " + outputFile);
85         }
86     }
87 
run()88     public void run() throws IOException {
89         try {
90             if (com.sun.tools.javadoc.Main.execute("javadoc",
91                                                    docletName,
92                                                    getClass().getClassLoader(),
93                                                    args) != 0) {
94                 throw new Error("Javadoc errors encountered.");
95             }
96             System.out.println("--> Output written to " + outputFile);
97         } finally {
98             out.close();
99         }
100     }
101 
102     /*
103      * Compare output of test run to expected output.
104      * Throw an Error if they don't match.
105      */
verify()106     public void verify() throws IOException {
107         BufferedReader thisRun =
108             new BufferedReader(new FileReader(outputFile));
109         BufferedReader expected =
110             new BufferedReader(new FileReader(expectedOutputFile));
111 
112         for (int lineNum = 1; true; lineNum++) {
113             String line1 = thisRun.readLine();
114             String line2 = expected.readLine();
115             if (line1 == null && line2 == null) {
116                 return;         // EOF with all lines matching
117             }
118             if (line1 == null || !line1.equals(line2)) {
119                 throw new Error(outputFile + ":" + lineNum +
120                                 ": output doesn't match");
121             }
122         }
123     }
124 
125 
println(Object o)126     public void println(Object o) throws IOException {
127         prln(0, o);
128     }
129 
println()130     public void println() throws IOException {
131         prln();
132     }
133 
printPackage(PackageDoc p)134     public void printPackage(PackageDoc p) throws IOException {
135         prPackage(0, p);
136     }
137 
printClass(ClassDoc cd)138     public void printClass(ClassDoc cd) throws IOException {
139         if (cd.isAnnotationType())
140             printAnnotationType((AnnotationTypeDoc)cd);
141         else
142             prClass(0, cd);
143     }
144 
printAnnotationType(AnnotationTypeDoc at)145     public void printAnnotationType(AnnotationTypeDoc at) throws IOException {
146         prAnnotationType(0, at);
147     }
148 
printField(FieldDoc f)149     public void printField(FieldDoc f) throws IOException {
150         prField(0, f);
151     }
152 
printParameter(Parameter p)153     public void printParameter(Parameter p) throws IOException {
154         prParameter(0, p);
155     }
156 
printMethod(MethodDoc m)157     public void printMethod(MethodDoc m) throws IOException {
158         prln(0, "method " + m);
159         prMethod(0, m);
160     }
161 
printAnnotationTypeElement(AnnotationTypeElementDoc e)162     public void printAnnotationTypeElement(AnnotationTypeElementDoc e)
163                                                         throws IOException {
164         prln(0, "element " + e);
165         prMethod(0, e);
166     }
167 
printConstructor(ConstructorDoc c)168     public void printConstructor(ConstructorDoc c) throws IOException {
169         prln(0, "constructor " + c);
170         prExecutable(0, c);
171     }
172 
173 
prPackage(int off, PackageDoc p)174     private void prPackage(int off, PackageDoc p) throws IOException {
175         prln(off, "package " + p);
176         prAnnotations(off + 2, p.annotations());
177     }
178 
prClass(int off, ClassDoc cd)179     private void prClass(int off, ClassDoc cd) throws IOException {
180         prln(off,
181              (cd.isInterface() ? "interface" : cd.isEnum() ? "enum" : "class")
182              + " " + cd);
183         prln(off + 2, "name: " + cd.simpleTypeName() + " / " +
184              cd.typeName() + " / " + cd.qualifiedTypeName());
185         prAnnotations(off + 2, cd.annotations());
186         prLabel(off + 2, "type parameters");
187         for (Type t : cd.typeParameters())
188             prln(off + 4, t);
189         prParamTags(off + 2, cd.typeParamTags());
190         prLabel(off + 2, "nested in");
191         prln(off + 4, cd.containingClass());
192         prLabel(off + 2, "superclass");
193         prln(off + 4, cd.superclassType());
194         prLabel(off + 2, "interfaces");
195         Type[] ts = cd.interfaceTypes();
196         Arrays.sort(ts);
197         for (Type t : ts)
198             prln(off + 4, t);
199         prLabel(off + 2, "enum constants");
200         for (FieldDoc f : cd.enumConstants())
201             prln(off + 4, f.name());
202         prLabel(off + 2, "fields");
203         for (FieldDoc f : cd.fields())
204             prln(off + 4, f.type() + " " + f.name());
205         prLabel(off + 2, "constructors");
206         for (ConstructorDoc c : cd.constructors())
207             prln(off + 4, c.name() + c.flatSignature());
208         prLabel(off + 2, "methods");
209         for (MethodDoc m : cd.methods())
210             prln(off + 4, typeUseString(m.returnType()) + " " +
211                           m.name() + m.flatSignature());
212     }
213 
prAnnotationType(int off, AnnotationTypeDoc at)214     private void prAnnotationType(int off, AnnotationTypeDoc at)
215                                                         throws IOException {
216         prln(off, "@interface " + at);
217         prAnnotations(off + 2, at.annotations());
218         prLabel(off + 2, "elements");
219         for (AnnotationTypeElementDoc e : at.elements()) {
220             String def = (e.defaultValue() == null)
221                                 ? ""
222                                 : " default " + e.defaultValue();
223             prln(off + 4, typeUseString(e.returnType()) + " " + e.name() +
224                           e.flatSignature() + def);
225         }
226     }
227 
prField(int off, FieldDoc f)228     private void prField(int off, FieldDoc f) throws IOException {
229         prln(off, "field " + typeUseString(f.type()) + " " + f.name());
230         prAnnotations(off + 2, f.annotations());
231     }
232 
prParameter(int off, Parameter p)233     private void prParameter(int off, Parameter p) throws IOException {
234         prln(off, "parameter " + p);
235         prAnnotations(off + 2, p.annotations());
236     }
237 
prMethod(int off, MethodDoc m)238     private void prMethod(int off, MethodDoc m) throws IOException {
239         prExecutable(off, m);
240         prLabel(off + 2, "returns");
241         prln(off + 4, typeUseString(m.returnType()));
242         prLabel(off + 2, "overridden type");
243         prln(off + 4, m.overriddenType());
244     }
245 
prExecutable(int off, ExecutableMemberDoc m)246     private void prExecutable(int off, ExecutableMemberDoc m)
247                                                         throws IOException {
248         if (!m.isAnnotationTypeElement()) {
249             prln(off + 2, "signature: " + m.flatSignature());
250             prln(off + 2, "           " + m.signature());
251         }
252         prAnnotations(off + 2, m.annotations());
253         prParamTags(off + 2, m.typeParamTags());
254         prParamTags(off + 2, m.paramTags());
255         prLabel(off + 2, "type parameters");
256         for (Type t : m.typeParameters())
257             prln(off + 4, t);
258         prLabel(off + 2, "throws");
259         Type[] ts = m.thrownExceptionTypes();
260         Arrays.sort(ts);
261         for (Type t : ts)
262             prln(off + 4, t);
263     }
264 
prAnnotations(int off, AnnotationDesc[] as)265     private void prAnnotations(int off, AnnotationDesc[] as)
266                                                         throws IOException {
267         prLabel(off, "annotations");
268         for (AnnotationDesc a : as)
269             prln(off + 2, a.toString());
270     }
271 
prParamTags(int off, ParamTag tags[])272     private void prParamTags(int off, ParamTag tags[]) throws IOException {
273         for (ParamTag tag : tags)
274             prParamTag(off, tag);
275     }
276 
prParamTag(int off, ParamTag tag)277     private void prParamTag(int off, ParamTag tag) throws IOException {
278         String name = tag.parameterName();
279         if (tag.isTypeParameter()) name = "<" + name + ">";
280         prln(off, "@param " + name + " " + tag.parameterComment());
281     }
282 
283 
typeUseString(Type t)284     private String typeUseString(Type t) {
285         return (t instanceof ClassDoc || t instanceof TypeVariable)
286                 ? t.typeName()
287                 : t.toString();
288     }
289 
290 
291     // Labels queued for possible printing.  Innermost is first in list.
292     List<Line> labels = new ArrayList<Line>();
293 
294     // Print label if its section is nonempty.
prLabel(int off, String s)295     void prLabel(int off, String s) {
296         while (!labels.isEmpty() && labels.get(0).off >= off)
297             labels.remove(0);
298         labels.add(0, new Line(off, s));
299     }
300 
301     // Print queued labels with offsets less than "off".
popLabels(int off)302     void popLabels(int off) throws IOException {
303         while (!labels.isEmpty()) {
304             Line label = labels.remove(0);
305             if (label.off < off)
306                 prln(label.off, label.o + ":");
307         }
308     }
309 
310     // Print "o" at given offset.
pr(int off, Object o)311     void pr(int off, Object o) throws IOException {
312         popLabels(off);
313         for (int i = 0; i < off; i++)
314             out.write(' ');
315         if (o != null)
316             out.write(o.toString());
317     }
318 
319     // Print "o" (if non-null) at given offset, then newline.
prln(int off, Object o)320     void prln(int off, Object o) throws IOException {
321         if (o != null) {
322             pr(off, o);
323             prln();
324         }
325     }
326 
327     // Print newline.
prln()328     void prln() throws IOException {
329         out.write('\n');        // don't want platform-dependent separator
330     }
331 
332 
333     static class Line {
334         int off;
335         Object o;
Line(int off, Object o)336         Line(int off, Object o) { this.off = off; this.o = o; }
337     }
338 }
339