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