test/langtools/jdk/javadoc/doclet/testFramesNoFrames/TestFramesNoFrames.java
changeset 54409 94986cf5e969
parent 54408 8fe16bf92ebd
parent 54373 13935056b05e
child 54410 7feb5e303c83
equal deleted inserted replaced
54408:8fe16bf92ebd 54409:94986cf5e969
     1 /*
       
     2  * Copyright (c) 2016, 2019, 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  * @test
       
    26  * @bug 8162353 8164747 8173707 8196202 8204303 8184205
       
    27  * @summary javadoc should provide a way to disable use of frames
       
    28  * @library /tools/lib ../../lib
       
    29  * @modules
       
    30  *      jdk.compiler/com.sun.tools.javac.api
       
    31  *      jdk.compiler/com.sun.tools.javac.main
       
    32  *      jdk.javadoc/jdk.javadoc.internal.tool
       
    33  * @build toolbox.ModuleBuilder toolbox.ToolBox
       
    34  * @build javadoc.tester.*
       
    35  * @run main TestFramesNoFrames
       
    36  */
       
    37 
       
    38 import java.io.*;
       
    39 import java.lang.annotation.Annotation;
       
    40 import java.lang.reflect.InvocationTargetException;
       
    41 import java.lang.reflect.Method;
       
    42 import java.nio.file.*;
       
    43 import java.util.*;
       
    44 import java.util.stream.Collectors;
       
    45 
       
    46 import toolbox.ModuleBuilder;
       
    47 import toolbox.ToolBox;
       
    48 
       
    49 import javadoc.tester.JavadocTester;
       
    50 
       
    51 public class TestFramesNoFrames extends JavadocTester {
       
    52 
       
    53     public static void main(String... args) throws Exception {
       
    54         TestFramesNoFrames tester = new TestFramesNoFrames();
       
    55         tester.generateSource();
       
    56         tester.runTests();
       
    57     }
       
    58 
       
    59     ToolBox tb = new ToolBox();
       
    60     Path gensrcModules = Paths.get("gensrc/modules");
       
    61     Path gensrcPackages = Paths.get("gensrc/packages");
       
    62 
       
    63     void generateSource() throws IOException {
       
    64         String[] modules = { "", "m1", "m2", "m3" };
       
    65         String[] packages = { "p1", "p2", "p3" };
       
    66         String[] classes = { "C1", "C2", "C3" };
       
    67         for (String m: modules) {
       
    68             ModuleBuilder mb = m.equals("") ? null : new ModuleBuilder(tb, m);
       
    69             for (String p: packages) {
       
    70                 Path pkgRoot;
       
    71                 if (m.equals("")) {
       
    72                     pkgRoot = gensrcPackages;
       
    73                 } else {
       
    74                     pkgRoot = gensrcModules.resolve(m);
       
    75                     mb.exports(m + p);
       
    76                 }
       
    77                 for (String c: classes) {
       
    78                     tb.writeJavaFiles(pkgRoot,
       
    79                         "package " + (m + p) + ";\n"
       
    80                         + "/** class " + (m + p + c).toUpperCase() + ". */\n"
       
    81                         + "public class " + (m + p + c).toUpperCase() + " { }"
       
    82                     );
       
    83                 }
       
    84             }
       
    85             if (!m.equals("")) {
       
    86                 mb.write(gensrcModules);
       
    87             }
       
    88         }
       
    89         tb.writeFile("overview.html",
       
    90                 "<html><body>This is the overview file</body></html>");
       
    91     }
       
    92 
       
    93     enum FrameKind {
       
    94         DEFAULT(),
       
    95         FRAMES("--frames"),
       
    96         NO_FRAMES("--no-frames");
       
    97         FrameKind(String... opts) {
       
    98             this.opts = Arrays.asList(opts);
       
    99         }
       
   100         final List<String> opts;
       
   101     }
       
   102 
       
   103     enum OverviewKind {
       
   104         DEFAULT(),
       
   105         OVERVIEW("-overview", "overview.html"),
       
   106         NO_OVERVIEW("-nooverview");
       
   107         OverviewKind(String... opts) {
       
   108             this.opts = Arrays.asList(opts);
       
   109         }
       
   110         final List<String> opts;
       
   111     }
       
   112 
       
   113     enum HtmlKind {
       
   114         HTML5("-html5");
       
   115         HtmlKind(String... opts) {
       
   116             this.opts = Arrays.asList(opts);
       
   117         }
       
   118         final List<String> opts;
       
   119     }
       
   120 
       
   121     @Override
       
   122     public void runTests() throws Exception {
       
   123         for (Method m : getClass().getDeclaredMethods()) {
       
   124             Annotation a = m.getAnnotation(Test.class);
       
   125             if (a != null) {
       
   126                 for (FrameKind fk : FrameKind.values()) {
       
   127                     for (OverviewKind ok : OverviewKind.values()) {
       
   128                         try {
       
   129                             out.println("Running test " + m.getName() + " " + fk + " " + ok);
       
   130                             Path base = Paths.get(m.getName() + "_" + fk + "_" + ok);
       
   131                             Files.createDirectories(base);
       
   132                             m.invoke(this, new Object[]{base, fk, ok});
       
   133                         } catch (InvocationTargetException e) {
       
   134                             Throwable cause = e.getCause();
       
   135                             throw (cause instanceof Exception) ? ((Exception)cause) : e;
       
   136                         }
       
   137                         out.println();
       
   138                     }
       
   139                 }
       
   140             }
       
   141         }
       
   142         printSummary();
       
   143     }
       
   144 
       
   145     void javadoc(Path outDir, FrameKind fKind, OverviewKind oKind, String... rest) {
       
   146         List<String> args = new ArrayList<>();
       
   147         args.add("-d");
       
   148         args.add(outDir.toString());
       
   149         args.addAll(fKind.opts);
       
   150         args.addAll(oKind.opts);
       
   151         args.addAll(Arrays.asList(rest));
       
   152         javadoc(args.toArray(new String[0]));
       
   153         checkExit(Exit.OK);
       
   154     }
       
   155 
       
   156     @Test
       
   157     public void testClass(Path base, FrameKind fKind, OverviewKind oKind) throws Exception {
       
   158         javadoc(base, fKind, oKind, gensrcPackages.resolve("p1/P1C1.java").toString());
       
   159 
       
   160         new Checker(fKind, oKind)
       
   161             .classes("p1.P1C1")
       
   162             .check();
       
   163     }
       
   164 
       
   165     @Test
       
   166     public void testClasses(Path base, FrameKind fKind, OverviewKind oKind) throws IOException {
       
   167         javadoc(base, fKind, oKind,
       
   168             gensrcPackages.resolve("p1/P1C1.java").toString(),
       
   169             gensrcPackages.resolve("p1/P1C2.java").toString(),
       
   170             gensrcPackages.resolve("p1/P1C3.java").toString());
       
   171 
       
   172         new Checker(fKind, oKind)
       
   173             .classes("p1.P1C1", "p1.P1C2", "p1.P1C3")
       
   174             .check();
       
   175     }
       
   176 
       
   177     @Test
       
   178     public void testPackage(Path base, FrameKind fKind, OverviewKind oKind) throws IOException {
       
   179         javadoc(base, fKind, oKind,
       
   180             "-sourcepath", gensrcPackages.toString(),
       
   181             "p1");
       
   182 
       
   183         new Checker(fKind, oKind)
       
   184             .classes("p1.P1C1", "p1.P1C2", "p1.P1C3")
       
   185             .check();
       
   186     }
       
   187 
       
   188     @Test
       
   189     public void testPackages(Path base, FrameKind fKind, OverviewKind oKind) throws IOException {
       
   190         javadoc(base, fKind, oKind,
       
   191             "-sourcepath", gensrcPackages.toString(),
       
   192             "p1", "p2", "p3");
       
   193 
       
   194         new Checker(fKind, oKind)
       
   195             .classes("p1.P1C1", "p1.P1C2", "p1.P1C3",
       
   196                     "p2.P2C1", "p2.P2C2", "p2.P2C3",
       
   197                     "p3.P3C1", "p3.P3C2", "p3.P3C3")
       
   198             .check();
       
   199     }
       
   200 
       
   201     @Test
       
   202     public void testModules(Path base, FrameKind fKind, OverviewKind oKind) throws IOException {
       
   203         javadoc(base, fKind, oKind,
       
   204             "--module-source-path", gensrcModules.toString(),
       
   205             "--module", "m1,m2,m3");
       
   206 
       
   207         new Checker(fKind, oKind)
       
   208             .classes("m1/m1p1.M1P1C1", "m1/m1p1.M1P1C2", "m1/m1p1.M1P1C3",
       
   209                     "m2/m2p1.M2P1C1", "m2/m2p1.M2P1C2", "m2/m2p1.M2P1C3",
       
   210                     "m3/m3p1.M3P1C1", "m3/m3p1.M3P1C2", "m3/m3p1.M3P1C3")
       
   211             .check();
       
   212     }
       
   213 
       
   214     /**
       
   215      * Check the contents of the generated output, according to the
       
   216      * specified options.
       
   217      */
       
   218     class Checker {
       
   219         private final FrameKind fKind;
       
   220         private final OverviewKind oKind;
       
   221         List<String> classes;
       
   222 
       
   223         private boolean frames;
       
   224         private boolean overview;
       
   225         private static final String framesWarning
       
   226                 = "javadoc: warning - You have specified to generate frames, by using the --frames option.\n"
       
   227                 + "The default is currently to not generate frames and the support for \n"
       
   228                 + "frames will be removed in a future release.\n"
       
   229                 + "To suppress this warning, remove the --frames option and avoid the use of frames.";
       
   230 
       
   231         Checker(FrameKind fKind, OverviewKind oKind) {
       
   232             this.fKind = fKind;
       
   233             this.oKind = oKind;
       
   234         }
       
   235 
       
   236         Checker classes(String... classes) {
       
   237             this.classes = Arrays.asList(classes);
       
   238             return this;
       
   239         }
       
   240 
       
   241         void check() throws IOException {
       
   242             switch (fKind) {
       
   243                 case FRAMES:
       
   244                     frames = true;
       
   245                     break;
       
   246 
       
   247                 case DEFAULT:
       
   248                 case NO_FRAMES:
       
   249                     frames = false;
       
   250                     break;
       
   251             }
       
   252 
       
   253             switch (oKind) {
       
   254                 case DEFAULT:
       
   255                     overview = (getPackageCount() > 1);
       
   256                     break;
       
   257 
       
   258                 case OVERVIEW:
       
   259                     overview = true;
       
   260                     break;
       
   261 
       
   262                 case NO_OVERVIEW:
       
   263                     overview = false;
       
   264                     break;
       
   265             }
       
   266 
       
   267             out.println("Checker: " + fKind + " " + oKind
       
   268                 + ": frames:" + frames + " overview:" + overview);
       
   269 
       
   270             checkAllClassesFiles();
       
   271             checkFrameFiles();
       
   272             checkOverviewSummary();
       
   273 
       
   274             checkIndex();
       
   275             checkNavBar();
       
   276             checkHelpDoc();
       
   277 
       
   278             checkWarning();
       
   279 
       
   280         }
       
   281 
       
   282         private void checkAllClassesFiles() {
       
   283             // these files are only generated in frames mode
       
   284             checkFiles(frames,
       
   285                     "allclasses-frame.html");
       
   286 
       
   287             checkFiles(false,
       
   288                     "allclasses.html");
       
   289 
       
   290             checkFiles(false,
       
   291                     "allclasses-noframe.html");
       
   292 
       
   293             if (frames) {
       
   294                 checkOutput("allclasses-frame.html", true,
       
   295                         classes.stream()
       
   296                             .map(c -> "title=\"class in " + packagePart(c) + "\" target=\"classFrame\">" + classPart(c) + "</a>")
       
   297                             .toArray(String[]::new));
       
   298             }
       
   299         }
       
   300 
       
   301         private void checkFrameFiles() {
       
   302             // these files are all only generated in frames mode
       
   303 
       
   304             // <module>/module-frame.html and <module>/module-type-frame.html files
       
   305             checkFiles(frames, classes.stream()
       
   306                 .filter(c -> isInModule(c))
       
   307                 .map(c -> modulePart(c))
       
   308                 .flatMap(m -> Arrays.asList(
       
   309                         m + "/module-frame.html",
       
   310                         m + "/module-type-frame.html").stream())
       
   311                 .collect(Collectors.toSet()));
       
   312 
       
   313             // <package>/package-frame.html files
       
   314             checkFiles(frames, classes.stream()
       
   315                     .map(c -> (isInModule(c) ? (modulePart(c) + "/") : "")
       
   316                                 + packagePart(c)
       
   317                                 + "/package-frame.html")
       
   318                     .collect(Collectors.toSet()));
       
   319         }
       
   320 
       
   321         private void checkHelpDoc() {
       
   322             // the Help page only describes Frame/NoFrames in frames mode
       
   323             checkOutput("help-doc.html", frames,
       
   324                         "<h2>Frames/No Frames</h2>");
       
   325         }
       
   326 
       
   327         private void checkIndex() {
       
   328             // the index.html page only contains frames and Javascript to default to no-frames view,
       
   329             // in frames mode
       
   330             checkOutput("index.html", frames,
       
   331                     "<iframe ",
       
   332                     "</iframe>",
       
   333                     "<body class=\"frames\" onload=\"loadFrames()\">\n"
       
   334                     + "<script type=\"text/javascript\">\n"
       
   335                     + "if (targetPage == \"\" || targetPage == \"undefined\")");
       
   336 
       
   337             // the index.html contains the overview if one
       
   338             // has been given, and not in frames mode
       
   339             checkOutput("index.html", !frames && oKind == OverviewKind.OVERVIEW,
       
   340                     "This is the overview file");
       
   341 
       
   342             // the index.html file contains a summary table
       
   343             // if an overview was generated and not in frames mode
       
   344             checkOutput("index.html", !frames && overview,
       
   345                     "<div class=\"overviewSummary\">\n<table");
       
   346 
       
   347             // the index.html file contains a redirect if
       
   348             // no frames and no overview
       
   349             checkOutput("index.html", !frames && !overview,
       
   350                     "<meta http-equiv=\"Refresh\" content=\"0;",
       
   351                     "<script type=\"text/javascript\">window.location.replace(");
       
   352 
       
   353             if (!frames && !overview) {
       
   354                 checkOutput("index.html", true,
       
   355                         "<noscript>\n<meta http-equiv=\"Refresh\" content=\"0;");
       
   356             }
       
   357         }
       
   358 
       
   359         private void checkNavBar() {
       
   360             // the files containing a navigation bar should only
       
   361             // contain FRAMES/NO-FRAMES links in frames mode
       
   362             List<String> navbarFiles = new ArrayList<>();
       
   363             navbarFiles.addAll(classes.stream()
       
   364                     .map(c -> (isInModule(c) ? (modulePart(c) + "/") : "")
       
   365                                 + toHtml(packageClassPart(c)))
       
   366                     .collect(Collectors.toSet()));
       
   367             for (String f : navbarFiles) {
       
   368                 checkOutput(f, frames,
       
   369                         "target=\"_top\">Frames</a>",
       
   370                         "target=\"_top\">No&nbsp;Frames</a>");
       
   371             }
       
   372         }
       
   373 
       
   374         private void checkOverviewSummary() {
       
   375             // To accommodate the historical behavior of generating
       
   376             // overview-summary.html in frames mode, the file
       
   377             // will still be generated in no-frames mode,
       
   378             // but will be a redirect to index.html
       
   379             checkFiles(overview,
       
   380                     "overview-summary.html");
       
   381             if (overview) {
       
   382                 checkOutput("overview-summary.html",  !frames,
       
   383                         "<link rel=\"canonical\" href=\"index.html\">",
       
   384                         "<script type=\"text/javascript\">window.location.replace('index.html')</script>",
       
   385                         "<meta http-equiv=\"Refresh\" content=\"0;index.html\">",
       
   386                         "<p><a href=\"index.html\">index.html</a></p>");
       
   387             }
       
   388         }
       
   389 
       
   390         private void checkWarning() {
       
   391             checkOutput(Output.OUT, frames, framesWarning);
       
   392         }
       
   393 
       
   394         private long getPackageCount() {
       
   395             return this.classes.stream()
       
   396                 .filter(name -> name.contains("."))
       
   397                 .map(name -> name.substring(0, name.lastIndexOf(".")))
       
   398                 .distinct()
       
   399                 .count();
       
   400         }
       
   401 
       
   402         private String classPart(String className) {
       
   403             int lastDot = className.lastIndexOf(".");
       
   404             return className.substring(lastDot + 1);
       
   405         }
       
   406 
       
   407         private String packagePart(String className) {
       
   408             int slash = className.indexOf("/");
       
   409             int lastDot = className.lastIndexOf(".");
       
   410             return className.substring(slash + 1, lastDot);
       
   411         }
       
   412 
       
   413         private String packageClassPart(String className) {
       
   414             int slash = className.indexOf("/");
       
   415             return className.substring(slash + 1);
       
   416         }
       
   417 
       
   418         private boolean isInModule(String className) {
       
   419             return className.contains("/");
       
   420         }
       
   421 
       
   422         private String modulePart(String className) {
       
   423             int slash = className.indexOf("/");
       
   424             return className.substring(0, slash);
       
   425         }
       
   426 
       
   427         private String toHtml(String className) {
       
   428             return className.replace(".", "/") + ".html";
       
   429         }
       
   430     }
       
   431 }