| /* |
| * Copyright (c) 2016, 2017, 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. |
| */ |
| |
| /* |
| * @test |
| * @bug 8162353 8164747 8173707 |
| * @summary javadoc should provide a way to disable use of frames |
| * @library /tools/lib ../lib |
| * @modules |
| * jdk.compiler/com.sun.tools.javac.api |
| * jdk.compiler/com.sun.tools.javac.main |
| * jdk.javadoc/jdk.javadoc.internal.tool |
| * @build toolbox.ModuleBuilder toolbox.ToolBox |
| * @build JavadocTester |
| * @run main TestFramesNoFrames |
| */ |
| |
| import java.io.*; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.nio.file.*; |
| import java.util.*; |
| import java.util.stream.Collectors; |
| |
| import toolbox.ModuleBuilder; |
| import toolbox.ToolBox; |
| |
| public class TestFramesNoFrames extends JavadocTester { |
| |
| public static void main(String... args) throws Exception { |
| TestFramesNoFrames tester = new TestFramesNoFrames(); |
| tester.generateSource(); |
| tester.runTests(); |
| } |
| |
| ToolBox tb = new ToolBox(); |
| Path gensrcModules = Paths.get("gensrc/modules"); |
| Path gensrcPackages = Paths.get("gensrc/packages"); |
| |
| void generateSource() throws IOException { |
| String[] modules = { "", "m1", "m2", "m3" }; |
| String[] packages = { "p1", "p2", "p3" }; |
| String[] classes = { "C1", "C2", "C3" }; |
| for (String m: modules) { |
| ModuleBuilder mb = m.equals("") ? null : new ModuleBuilder(tb, m); |
| for (String p: packages) { |
| Path pkgRoot; |
| if (m.equals("")) { |
| pkgRoot = gensrcPackages; |
| } else { |
| pkgRoot = gensrcModules.resolve(m); |
| mb.exports(m + p); |
| } |
| for (String c: classes) { |
| tb.writeJavaFiles(pkgRoot, |
| "package " + (m + p) + ";\n" |
| + "/** class " + (m + p + c).toUpperCase() + ". */\n" |
| + "public class " + (m + p + c).toUpperCase() + " { }" |
| ); |
| } |
| } |
| if (!m.equals("")) { |
| mb.write(gensrcModules); |
| } |
| } |
| tb.writeFile("overview.html", |
| "<html><body>This is the overview file</body></html>"); |
| } |
| |
| enum FrameKind { |
| DEFAULT(), |
| FRAMES("--frames"), |
| NO_FRAMES("--no-frames"); |
| FrameKind(String... opts) { |
| this.opts = Arrays.asList(opts); |
| } |
| final List<String> opts; |
| } |
| |
| enum OverviewKind { |
| DEFAULT(), |
| OVERVIEW("-overview", "overview.html"), |
| NO_OVERVIEW("-nooverview"); |
| OverviewKind(String... opts) { |
| this.opts = Arrays.asList(opts); |
| } |
| final List<String> opts; |
| } |
| |
| enum HtmlKind { |
| HTML4("-html4"), |
| HTML5("-html5"); |
| HtmlKind(String... opts) { |
| this.opts = Arrays.asList(opts); |
| } |
| final List<String> opts; |
| } |
| |
| @Override |
| public void runTests() throws Exception { |
| for (Method m : getClass().getDeclaredMethods()) { |
| Annotation a = m.getAnnotation(Test.class); |
| if (a != null) { |
| for (FrameKind fk : FrameKind.values()) { |
| for (OverviewKind ok : OverviewKind.values()) { |
| for (HtmlKind hk : HtmlKind.values()) { |
| try { |
| out.println("Running test " + m.getName() + " " + fk + " " + ok + " " + hk); |
| Path base = Paths.get(m.getName() + "_" + fk + "_" + ok + "_" + hk); |
| Files.createDirectories(base); |
| m.invoke(this, new Object[]{base, fk, ok, hk}); |
| } catch (InvocationTargetException e) { |
| Throwable cause = e.getCause(); |
| throw (cause instanceof Exception) ? ((Exception) cause) : e; |
| } |
| out.println(); |
| } |
| } |
| } |
| } |
| } |
| printSummary(); |
| } |
| |
| void javadoc(Path outDir, FrameKind fKind, OverviewKind oKind, HtmlKind hKind, String... rest) { |
| List<String> args = new ArrayList<>(); |
| args.add("-d"); |
| args.add(outDir.toString()); |
| args.addAll(fKind.opts); |
| args.addAll(oKind.opts); |
| args.addAll(hKind.opts); |
| args.addAll(Arrays.asList(rest)); |
| javadoc(args.toArray(new String[0])); |
| checkExit(Exit.OK); |
| } |
| |
| @Test |
| void testClass(Path base, FrameKind fKind, OverviewKind oKind, HtmlKind hKind) throws Exception { |
| javadoc(base, fKind, oKind, hKind, |
| gensrcPackages.resolve("p1/P1C1.java").toString()); |
| |
| new Checker(fKind, oKind, hKind) |
| .classes("p1.P1C1") |
| .check(); |
| } |
| |
| @Test |
| void testClasses(Path base, FrameKind fKind, OverviewKind oKind, HtmlKind hKind) throws IOException { |
| javadoc(base, fKind, oKind, hKind, |
| gensrcPackages.resolve("p1/P1C1.java").toString(), |
| gensrcPackages.resolve("p1/P1C2.java").toString(), |
| gensrcPackages.resolve("p1/P1C3.java").toString()); |
| |
| new Checker(fKind, oKind, hKind) |
| .classes("p1.P1C1", "p1.P1C2", "p1.P1C3") |
| .check(); |
| } |
| |
| @Test |
| void testPackage(Path base, FrameKind fKind, OverviewKind oKind, HtmlKind hKind) throws IOException { |
| javadoc(base, fKind, oKind, hKind, |
| "-sourcepath", gensrcPackages.toString(), |
| "p1"); |
| |
| new Checker(fKind, oKind, hKind) |
| .classes("p1.P1C1", "p1.P1C2", "p1.P1C3") |
| .check(); |
| } |
| |
| @Test |
| void testPackages(Path base, FrameKind fKind, OverviewKind oKind, HtmlKind hKind) throws IOException { |
| javadoc(base, fKind, oKind, hKind, |
| "-sourcepath", gensrcPackages.toString(), |
| "p1", "p2", "p3"); |
| |
| new Checker(fKind, oKind, hKind) |
| .classes("p1.P1C1", "p1.P1C2", "p1.P1C3", |
| "p2.P2C1", "p2.P2C2", "p2.P2C3", |
| "p3.P3C1", "p3.P3C2", "p3.P3C3") |
| .check(); |
| } |
| |
| @Test |
| void testModules(Path base, FrameKind fKind, OverviewKind oKind, HtmlKind hKind) throws IOException { |
| javadoc(base, fKind, oKind, hKind, |
| "--module-source-path", gensrcModules.toString(), |
| "--module", "m1,m2,m3"); |
| |
| new Checker(fKind, oKind, hKind) |
| .classes("m1/m1p1.M1P1C1", "m1/m1p1.M1P1C2", "m1/m1p1.M1P1C3", |
| "m2/m2p1.M2P1C1", "m2/m2p1.M2P1C2", "m2/m2p1.M2P1C3", |
| "m3/m3p1.M3P1C1", "m3/m3p1.M3P1C2", "m3/m3p1.M3P1C3") |
| .check(); |
| } |
| |
| /** |
| * Check the contents of the generated output, according to the |
| * specified options. |
| */ |
| class Checker { |
| private final FrameKind fKind; |
| private final OverviewKind oKind; |
| private final HtmlKind hKind; |
| List<String> classes; |
| |
| private boolean frames; |
| private boolean overview; |
| |
| Checker(FrameKind fKind, OverviewKind oKind, HtmlKind hKind) { |
| this.fKind = fKind; |
| this.oKind = oKind; |
| this.hKind = hKind; |
| } |
| |
| Checker classes(String... classes) { |
| this.classes = Arrays.asList(classes); |
| return this; |
| } |
| |
| void check() throws IOException { |
| switch (fKind) { |
| case DEFAULT: |
| case FRAMES: |
| frames = true; |
| break; |
| |
| case NO_FRAMES: |
| frames = false; |
| break; |
| } |
| |
| switch (oKind) { |
| case DEFAULT: |
| overview = (getPackageCount() > 1); |
| break; |
| |
| case OVERVIEW: |
| overview = true; |
| break; |
| |
| case NO_OVERVIEW: |
| overview = false; |
| break; |
| } |
| |
| checkAllClassesFiles(); |
| checkFrameFiles(); |
| checkOverviewSummary(); |
| |
| checkIndex(); |
| checkNavBar(); |
| checkHelpDoc(); |
| |
| } |
| |
| private void checkAllClassesFiles() { |
| // these files are only generated in frames mode |
| checkFiles(frames, |
| "allclasses-frame.html", |
| "allclasses-noframe.html"); |
| |
| // this file is only generated when not in frames mode |
| checkFiles(!frames, |
| "allclasses.html"); |
| |
| if (frames) { |
| checkOutput("allclasses-frame.html", true, |
| classes.stream() |
| .map(c -> "title=\"class in " + packagePart(c) + "\" target=\"classFrame\">" + classPart(c) + "</a>") |
| .toArray(String[]::new)); |
| checkOutput("allclasses-noframe.html", false, |
| "target=\"classFrame\">"); |
| } else { |
| checkOutput("allclasses.html", false, |
| "target=\"classFrame\">"); |
| |
| } |
| } |
| |
| private void checkFrameFiles() { |
| // these files are all only generated in frames mode |
| |
| // <module>-frame.html and <module>-type-frame.html files |
| checkFiles(frames, classes.stream() |
| .filter(c -> isInModule(c)) |
| .map(c -> modulePart(c)) |
| .flatMap(m -> Arrays.asList( |
| m + "-frame.html", |
| m + "-type-frame.html").stream()) |
| .collect(Collectors.toSet())); |
| |
| // <package>/package-frame.html files |
| checkFiles(frames, classes.stream() |
| .map(c -> packagePart(c) + "/package-frame.html") |
| .collect(Collectors.toSet())); |
| } |
| |
| private void checkHelpDoc() { |
| // the Help page only describes Frame/NoFrames in frames mode |
| checkOutput("help-doc.html", frames, |
| "<h2>Frames/No Frames</h2>"); |
| } |
| |
| private void checkIndex() { |
| // the index.html page only contains frames and Javascript to default to no-frames view, |
| // in frames mode |
| checkOutput("index.html", frames, |
| "<iframe ", |
| "</iframe>", |
| "<body onload=\"loadFrames()\">\n" |
| + "<script type=\"text/javascript\">\n" |
| + "if (targetPage == \"\" || targetPage == \"undefined\")"); |
| |
| // the index.html contains the overview if one |
| // has been given, and not in frames mode |
| checkOutput("index.html", !frames && oKind == OverviewKind.OVERVIEW, |
| "This is the overview file"); |
| |
| // the index.html file contains a summary table |
| // if an overview was generated and not in frames mode |
| checkOutput("index.html", !frames && overview, |
| "<table class=\"overviewSummary\""); |
| |
| // the index.html file contains a redirect if |
| // no frames and no overview |
| checkOutput("index.html", !frames && !overview, |
| "<meta http-equiv=\"Refresh\" content=\"0;", |
| "<script type=\"text/javascript\">window.location.replace("); |
| |
| // the index.html file <meta> refresh should only use <noscript> in HTML 5 |
| if (!frames && !overview) { |
| checkOutput("index.html", hKind == HtmlKind.HTML5, |
| "<noscript>\n<meta http-equiv=\"Refresh\" content=\"0;"); |
| } |
| } |
| |
| private void checkNavBar() { |
| // the files containing a navigation bar should only |
| // contain FRAMES/NO-FRAMES links in frames mode |
| List<String> navbarFiles = new ArrayList<>(); |
| navbarFiles.addAll(classes.stream() |
| .map(c -> toHtml(packageClassPart(c))) |
| .collect(Collectors.toSet())); |
| for (String f : navbarFiles) { |
| checkOutput(f, frames, |
| "target=\"_top\">Frames</a>", |
| "target=\"_top\">No Frames</a>"); |
| } |
| } |
| |
| private void checkOverviewSummary() { |
| // the overview-summary.html file only appears if |
| // in frames mode and (overview requested or multiple packages) |
| checkFiles(frames && overview, |
| "overview-summary.html"); |
| } |
| |
| private long getPackageCount() { |
| return this.classes.stream() |
| .filter(name -> name.contains(".")) |
| .map(name -> name.substring(0, name.lastIndexOf("."))) |
| .distinct() |
| .count(); |
| } |
| |
| private String classPart(String className) { |
| int lastDot = className.lastIndexOf("."); |
| return className.substring(lastDot + 1); |
| } |
| |
| private String packagePart(String className) { |
| int slash = className.indexOf("/"); |
| int lastDot = className.lastIndexOf("."); |
| return className.substring(slash + 1, lastDot); |
| } |
| |
| private String packageClassPart(String className) { |
| int slash = className.indexOf("/"); |
| return className.substring(slash + 1); |
| } |
| |
| private boolean isInModule(String className) { |
| return className.contains("/"); |
| } |
| |
| private String modulePart(String className) { |
| int slash = className.indexOf("/"); |
| return className.substring(0, slash); |
| } |
| |
| private String toHtml(String className) { |
| return className.replace(".", "/") + ".html"; |
| } |
| } |
| } |