1 /*
   2  * Copyright (c) 2016, 2017, 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 8178070
  27  * @summary Test packages table in module summary pages
  28  * @library /tools/lib ../lib
  29  * @modules jdk.compiler/com.sun.tools.javac.api
  30  *          jdk.compiler/com.sun.tools.javac.main
  31  *          jdk.javadoc/jdk.javadoc.internal.tool
  32  * @build toolbox.ModuleBuilder toolbox.ToolBox JavadocTester
  33  * @run main TestModulePackages
  34  */
  35 
  36 import java.io.IOException;
  37 import java.nio.file.Path;
  38 import java.nio.file.Paths;
  39 import java.util.Set;
  40 
  41 import toolbox.ModuleBuilder;
  42 import toolbox.ToolBox;
  43 
  44 public class TestModulePackages extends JavadocTester {
  45     enum TabKind { EXPORTS, OPENS, CONCEALED };
  46     enum ColKind { EXPORTED_TO, OPENED_TO };
  47 
  48     public static void main(String... args) throws Exception {
  49         TestModulePackages tester = new TestModulePackages();
  50         tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
  51     }
  52 
  53     private final ToolBox tb;
  54 
  55     public TestModulePackages() {
  56         tb = new ToolBox();
  57     }
  58 
  59     // @Test: See: https://bugs.openjdk.java.net/browse/JDK-8193107
  60     public void empty(Path base) throws Exception {
  61         Path src = base.resolve("src");
  62         new ModuleBuilder(tb, "m")
  63                 .comment("empty module")
  64                 .write(src);
  65 
  66         javadoc("-d", base.resolve("out").toString(),
  67                 "-quiet",
  68                 "-noindex",
  69                 "--module-source-path", src.toString(),
  70                 "--module", "m");
  71 
  72         checkExit(Exit.OK);
  73         checkOutput("m-summary.html", false,
  74                 "<h3>Packages</h3>\n"
  75                 + "<table class=\"packagesSummary\" summary=\"Packages table, "
  76                 + "listing packages, and an explanation\">");
  77     }
  78 
  79     @Test
  80     public void exportSingle(Path base) throws Exception {
  81         Path src = base.resolve("src");
  82         new ModuleBuilder(tb, "m")
  83                 .comment("exports single package to all")
  84                 .exports("p")
  85                 .classes("package p; public class C { }")
  86                 .write(src);
  87 
  88         javadoc("-d", base.resolve("out").toString(),
  89                 "-quiet",
  90                 "-noindex",
  91                 "--module-source-path", src.toString(),
  92                 "--module", "m");
  93 
  94         checkExit(Exit.OK);
  95         checkCaption("m", TabKind.EXPORTS);
  96         checkTableHead("m");
  97         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
  98     }
  99 
 100     @Test
 101     public void exportMultiple(Path base) throws Exception {
 102         Path src = base.resolve("src");
 103         new ModuleBuilder(tb, "m")
 104                 .comment("exports multiple packages to all")
 105                 .exports("p")
 106                 .exports("q")
 107                 .classes("package p; public class C { }")
 108                 .classes("package q; public class D { }")
 109                 .write(src);
 110 
 111         javadoc("-d", base.resolve("out").toString(),
 112                 "-quiet",
 113                 "-noindex",
 114                 "--module-source-path", src.toString(),
 115                 "--module", "m");
 116 
 117         checkExit(Exit.OK);
 118         checkCaption("m", TabKind.EXPORTS);
 119         checkTableHead("m");
 120         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 121         checkPackageRow("m", "q", "i1", null, null, "&nbsp;");
 122     }
 123 
 124     @Test
 125     public void exportSomeQualified(Path base) throws Exception {
 126         Path src = base.resolve("src");
 127         new ModuleBuilder(tb, "m")
 128                 .comment("exports multiple packages, some qualified")
 129                 .exports("p")
 130                 .exportsTo("q", "other")
 131                 .classes("package p; public class C { }")
 132                 .classes("package q; public class D { }")
 133                 .write(src);
 134 
 135         new ModuleBuilder(tb, "other")
 136                 .comment("dummy module for target of export")
 137                 .write(src);
 138 
 139         javadoc("-d", base.resolve("out-api").toString(),
 140                 "-quiet",
 141                 "-noindex",
 142                 "--module-source-path", src.toString(),
 143                 "--module", "m,other");
 144 
 145         checkExit(Exit.OK);
 146         checkCaption("m", TabKind.EXPORTS);
 147         checkTableHead("m");
 148         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 149 
 150         javadoc("-d", base.resolve("out-all").toString(),
 151                 "-quiet",
 152                 "-noindex",
 153                 "--show-module-contents", "all",
 154                 "--module-source-path", src.toString(),
 155                 "--module", "m,other");
 156 
 157         checkExit(Exit.OK);
 158         checkCaption("m", TabKind.EXPORTS);
 159         checkTableHead("m", ColKind.EXPORTED_TO);
 160         checkPackageRow("m", "p", "i0", "All Modules", null, "&nbsp;");
 161         checkPackageRow("m", "q", "i1",
 162                 "<a href=\"other-summary.html\">other</a>", null, "&nbsp;");
 163     }
 164 
 165     @Test
 166     public void exportWithConcealed(Path base) throws Exception {
 167         Path src = base.resolve("src");
 168         new ModuleBuilder(tb, "m")
 169                 .comment("exports package, has concealed package")
 170                 .exports("p")
 171                 .classes("package p; public class C { }")
 172                 .classes("package q; public class D { }")
 173                 .write(src);
 174 
 175         javadoc("-d", base.resolve("out-api").toString(),
 176                 "-quiet",
 177                 "-noindex",
 178                 "--module-source-path", src.toString(),
 179                 "--module", "m");
 180 
 181         checkExit(Exit.OK);
 182         checkCaption("m", TabKind.EXPORTS);
 183         checkTableHead("m");
 184         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 185 
 186         javadoc("-d", base.resolve("out-all").toString(),
 187                 "-quiet",
 188                 "-noindex",
 189                 "--show-module-contents", "all",
 190                 "--show-packages", "all",
 191                 "--module-source-path", src.toString(),
 192                 "--module", "m");
 193 
 194         checkExit(Exit.OK);
 195         checkCaption("m", TabKind.EXPORTS, TabKind.CONCEALED);
 196         checkTableHead("m", ColKind.EXPORTED_TO);
 197         checkPackageRow("m", "p", "i0", "All Modules", null, "&nbsp;");
 198         checkPackageRow("m", "q", "i1", "None", null, "&nbsp;");
 199     }
 200 
 201     @Test
 202     public void exportOpenWithConcealed(Path base) throws Exception {
 203         Path src = base.resolve("src");
 204         new ModuleBuilder(tb, "m")
 205                 .comment("exports and opens qual and unqual, with concealed")
 206                 .exports("e.all")
 207                 .exportsTo("e.other", "other")
 208                 .opens("o.all")
 209                 .opensTo("o.other", "other")
 210                 .exports("eo")
 211                 .opens("eo")
 212                 .classes("package e.all; public class CEAll { }")
 213                 .classes("package e.other; public class CEOther { }")
 214                 .classes("package o.all; public class COAll { }")
 215                 .classes("package o.other; public class COOther { }")
 216                 .classes("package eo; public class CEO { }")
 217                 .classes("package c; public class C { }")
 218                 .write(src);
 219 
 220         new ModuleBuilder(tb, "other")
 221                 .comment("dummy module for target of export and open")
 222                 .write(src);
 223 
 224         javadoc("-d", base.resolve("out-api").toString(),
 225                 "-quiet",
 226                 "-noindex",
 227                 "--module-source-path", src.toString(),
 228                 "--module", "m,other");
 229 
 230         checkExit(Exit.OK);
 231         checkCaption("m", TabKind.EXPORTS, TabKind.OPENS);
 232         checkTableHead("m", ColKind.EXPORTED_TO, ColKind.OPENED_TO);
 233         checkPackageRow("m", "e.all", "i0", "All Modules", "None", "&nbsp;");
 234         checkPackageRow("m", "eo", "i1", "All Modules", "All Modules", "&nbsp;");
 235 
 236         javadoc("-d", base.resolve("out-all").toString(),
 237                 "-quiet",
 238                 "-noindex",
 239                 "--show-module-contents", "all",
 240                 "--show-packages", "all",
 241                 "--module-source-path", src.toString(),
 242                 "--module", "m,other");
 243 
 244         checkExit(Exit.OK);
 245         checkCaption("m", TabKind.EXPORTS, TabKind.OPENS, TabKind.CONCEALED);
 246         checkTableHead("m", ColKind.EXPORTED_TO, ColKind.OPENED_TO);
 247         checkPackageRow("m", "c", "i0", "None", "None", "&nbsp;");
 248         checkPackageRow("m", "e.all", "i1", "All Modules", "None", "&nbsp;");
 249         checkPackageRow("m", "e.other", "i2",
 250                 "<a href=\"other-summary.html\">other</a>", "None", "&nbsp;");
 251         checkPackageRow("m", "eo", "i3", "All Modules", "All Modules", "&nbsp;");
 252         checkPackageRow("m", "o.all", "i4", "None", "All Modules", "&nbsp;");
 253         checkPackageRow("m", "o.other", "i5", "None",
 254                 "<a href=\"other-summary.html\">other</a>", "&nbsp;");
 255     }
 256 
 257     @Test
 258     public void openModule(Path base) throws Exception {
 259         Path src = base.resolve("src");
 260         new ModuleBuilder(tb, true, "m")
 261                 .comment("open module")
 262                 .classes("/** implicitly open package */ package p;")
 263                 .classes("package p; public class C { } ")
 264                 .classes("/** implicitly open package */ package q;")
 265                 .classes("package q; public class D { }")
 266                 .write(src);
 267 
 268         javadoc("-d", base.resolve("out").toString(),
 269                 "-quiet",
 270                 "-noindex",
 271                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 272                 "--module-source-path", src.toString(),
 273                 "--module", "m");
 274 
 275         checkExit(Exit.OK);
 276         checkCaption("m", TabKind.OPENS);
 277         checkTableHead("m");
 278         checkPackageRow("m", "p", "i0", null, null,
 279                 "\n<div class=\"block\">implicitly open package</div>\n");
 280         checkPackageRow("m", "q", "i1", null, null,
 281                 "\n<div class=\"block\">implicitly open package</div>\n");
 282     }
 283     @Test
 284     public void openSingle(Path base) throws Exception {
 285         Path src = base.resolve("src");
 286         new ModuleBuilder(tb, "m")
 287                 .comment("opens single package to all")
 288                 .opens("p")
 289                 .classes("package p; public class C { }")
 290                 .write(src);
 291 
 292         javadoc("-d", base.resolve("out").toString(),
 293                 "-quiet",
 294                 "-noindex",
 295                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 296                 "--module-source-path", src.toString(),
 297                 "--module", "m");
 298 
 299         checkExit(Exit.OK);
 300         checkCaption("m", TabKind.OPENS);
 301         checkTableHead("m");
 302         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 303     }
 304 
 305     @Test
 306     public void openMultiple(Path base) throws Exception {
 307         Path src = base.resolve("src");
 308         new ModuleBuilder(tb, "m")
 309                 .comment("opens multiple packages to all")
 310                 .opens("p")
 311                 .opens("q")
 312                 .classes("package p; public class C { }")
 313                 .classes("package q; public class D { }")
 314                 .write(src);
 315 
 316         javadoc("-d", base.resolve("out").toString(),
 317                 "-quiet",
 318                 "-noindex",
 319                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 320                 "--module-source-path", src.toString(),
 321                 "--module", "m");
 322 
 323         checkExit(Exit.OK);
 324         checkCaption("m", TabKind.OPENS);
 325         checkTableHead("m");
 326         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 327         checkPackageRow("m", "q", "i1", null, null, "&nbsp;");
 328     }
 329 
 330     @Test
 331     public void openSomeQualified(Path base) throws Exception {
 332         Path src = base.resolve("src");
 333         new ModuleBuilder(tb, "m")
 334                 .comment("opens multiple packages, some qualified")
 335                 .opens("p")
 336                 .opensTo("q", "other")
 337                 .classes("package p; public class C { }")
 338                 .classes("package q; public class D { }")
 339                 .write(src);
 340 
 341         new ModuleBuilder(tb, "other")
 342                 .comment("dummy module for target of export")
 343                 .write(src);
 344 
 345         javadoc("-d", base.resolve("out-api").toString(),
 346                 "-quiet",
 347                 "-noindex",
 348                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 349                 "--module-source-path", src.toString(),
 350                 "--module", "m,other");
 351 
 352         checkExit(Exit.OK);
 353         checkCaption("m", TabKind.OPENS);
 354         checkTableHead("m");
 355         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 356 
 357         javadoc("-d", base.resolve("out-all").toString(),
 358                 "-quiet",
 359                 "-noindex",
 360                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 361                 "--show-module-contents", "all",
 362                 "--module-source-path", src.toString(),
 363                 "--module", "m,other");
 364 
 365         checkExit(Exit.OK);
 366         checkCaption("m", TabKind.OPENS);
 367         checkTableHead("m", ColKind.OPENED_TO);
 368         checkPackageRow("m", "p", "i0", null, "All Modules", "&nbsp;");
 369         checkPackageRow("m", "q", "i1", null,
 370                 "<a href=\"other-summary.html\">other</a>", "&nbsp;");
 371     }
 372 
 373     @Test
 374     public void openWithConcealed(Path base) throws Exception {
 375         Path src = base.resolve("src");
 376         new ModuleBuilder(tb, "m")
 377                 .comment("opens package, has concealed package")
 378                 .opens("p")
 379                 .classes("package p; public class C { }")
 380                 .classes("package q; public class D { }")
 381                 .write(src);
 382 
 383         javadoc("-d", base.resolve("out-api").toString(),
 384                 "-quiet",
 385                 "-noindex",
 386                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 387                 "--module-source-path", src.toString(),
 388                 "--module", "m");
 389 
 390         checkExit(Exit.OK);
 391         checkCaption("m", TabKind.OPENS);
 392         checkTableHead("m");
 393         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 394 
 395         javadoc("-d", base.resolve("out-all").toString(),
 396                 "-quiet",
 397                 "-noindex",
 398                 "--show-module-contents", "all",
 399                 "--show-packages", "all",
 400                 "--module-source-path", src.toString(),
 401                 "--module", "m");
 402 
 403         checkExit(Exit.OK);
 404         checkCaption("m", TabKind.OPENS, TabKind.CONCEALED);
 405         checkTableHead("m", ColKind.OPENED_TO);
 406         checkPackageRow("m", "p", "i0", null, "All Modules", "&nbsp;");
 407         checkPackageRow("m", "q", "i1", null, "None", "&nbsp;");
 408     }
 409 
 410 
 411     private void checkCaption(String moduleName, TabKind... kinds) {
 412         String expect;
 413         if (kinds.length > 1) {
 414             Set<TabKind> kindSet = Set.of(kinds);
 415             StringBuilder sb = new StringBuilder();
 416             sb.append("<caption>"
 417                         + "<span id=\"t0\" class=\"activeTableTab\">"
 418                         + "<span>All Packages</span>"
 419                         + "<span class=\"tabEnd\">&nbsp;</span></span>");
 420             if (kindSet.contains(TabKind.EXPORTS)) {
 421                 sb.append("<span id=\"t1\" class=\"tableTab\">"
 422                         + "<span><a href=\"javascript:showPkgs(1);\">Exports</a></span>"
 423                         + "<span class=\"tabEnd\">&nbsp;</span></span>");
 424             }
 425             if (kindSet.contains(TabKind.OPENS)) {
 426                 sb.append("<span id=\"t2\" class=\"tableTab\">"
 427                         + "<span><a href=\"javascript:showPkgs(2);\">Opens</a></span>"
 428                         + "<span class=\"tabEnd\">&nbsp;</span></span>");
 429             }
 430             if (kindSet.contains(TabKind.CONCEALED)) {
 431                 sb.append("<span id=\"t3\" class=\"tableTab\"><span>"
 432                         + "<a href=\"javascript:showPkgs(4);\">Concealed</a></span>"
 433                         + "<span class=\"tabEnd\">&nbsp;</span></span>");
 434             }
 435             sb.append("</caption>");
 436             expect = sb.toString();
 437         } else {
 438             TabKind k = kinds[0];
 439             String name = k.toString().charAt(0) + k.toString().substring(1).toLowerCase();
 440             expect = "<caption>"
 441                         + "<span>" + name + "</span>"
 442                         + "<span class=\"tabEnd\">&nbsp;</span>"
 443                         + "</caption>";
 444         }
 445 
 446         checkOutput(moduleName + "-summary.html", true, expect);
 447     }
 448 
 449 
 450     private void checkTableHead(String moduleName, ColKind... kinds) {
 451         Set<ColKind> kindSet = Set.of(kinds);
 452         StringBuilder sb = new StringBuilder();
 453         sb.append("<tr>\n"
 454             + "<th class=\"colFirst\" scope=\"col\">Package</th>\n");
 455         if (kindSet.contains(ColKind.EXPORTED_TO)) {
 456             sb.append("<th class=\"colSecond\" scope=\"col\">Exported To Modules</th>\n");
 457         }
 458         if (kindSet.contains(ColKind.OPENED_TO)) {
 459             sb.append("<th class=\"colSecond\" scope=\"col\">Opened To Modules</th>\n");
 460         }
 461         sb.append("<th class=\"colLast\" scope=\"col\">Description</th>\n"
 462             + "</tr>");
 463 
 464         checkOutput(moduleName + "-summary.html", true, sb.toString());
 465     }
 466 
 467     private void checkPackageRow(String moduleName, String packageName,
 468             String id, String exportedTo, String openedTo, String desc) {
 469         StringBuilder sb = new StringBuilder();
 470         int idNum = Integer.parseInt(id.substring(1));
 471         String color = (idNum % 2 == 1 ? "rowColor" : "altColor");
 472         sb.append("<tr class=\"" + color + "\" id=\"" + id + "\">\n"
 473                 + "<th class=\"colFirst\" scope=\"row\">"
 474                 + "<a href=\"" + packageName.replace('.', '/') + "/package-summary.html\">"
 475                 + packageName + "</a></th>\n");
 476         if (exportedTo != null) {
 477             sb.append("<td class=\"colSecond\">" + exportedTo + "</td>\n");
 478         }
 479         if (openedTo != null) {
 480             sb.append("<td class=\"colSecond\">" + openedTo + "</td>\n");
 481         }
 482         sb.append("<td class=\"colLast\">" + desc + "</td>");
 483 
 484         checkOutput(moduleName + "-summary.html", true, sb.toString());
 485     }
 486 
 487 }
 488