1 /*
   2  * Copyright (c) 2016, 2020, 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 8196201 8184205
  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 javadoc.tester.*
  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 javadoc.tester.JavadocTester;
  42 import toolbox.ModuleBuilder;
  43 import toolbox.ToolBox;
  44 
  45 public class TestModulePackages extends JavadocTester {
  46     enum TabKind { EXPORTS, OPENS, CONCEALED };
  47     enum ColKind { EXPORTED_TO, OPENED_TO };
  48 
  49     public static void main(String... args) throws Exception {
  50         TestModulePackages tester = new TestModulePackages();
  51         tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
  52     }
  53 
  54     private final ToolBox tb;
  55 
  56     public TestModulePackages() {
  57         tb = new ToolBox();
  58     }
  59 
  60     // @Test: See: https://bugs.openjdk.java.net/browse/JDK-8193107
  61     public void empty(Path base) throws Exception {
  62         Path src = base.resolve("src");
  63         new ModuleBuilder(tb, "m")
  64                 .comment("empty module")
  65                 .write(src);
  66 
  67         javadoc("-d", base.resolve("out").toString(),
  68                 "-quiet",
  69                 "-noindex",
  70                 "--module-source-path", src.toString(),
  71                 "--module", "m");
  72 
  73         checkExit(Exit.OK);
  74         checkOutput("m/module-summary.html", false,
  75                 """
  76                     <h3>Packages</h3>
  77                     <table class="packages-summary" summary="Packages table, listing packages, and an explanation">""");
  78     }
  79 
  80     @Test
  81     public void exportSingle(Path base) throws Exception {
  82         Path src = base.resolve("src");
  83         new ModuleBuilder(tb, "m")
  84                 .comment("exports single package to all")
  85                 .exports("p")
  86                 .classes("package p; public class C { }")
  87                 .write(src);
  88 
  89         javadoc("-d", base.resolve("out").toString(),
  90                 "-quiet",
  91                 "-noindex",
  92                 "--module-source-path", src.toString(),
  93                 "--module", "m");
  94 
  95         checkExit(Exit.OK);
  96         checkCaption("m", TabKind.EXPORTS);
  97         checkTableHead("m");
  98         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
  99     }
 100 
 101     @Test
 102     public void exportMultiple(Path base) throws Exception {
 103         Path src = base.resolve("src");
 104         new ModuleBuilder(tb, "m")
 105                 .comment("exports multiple packages to all")
 106                 .exports("p")
 107                 .exports("q")
 108                 .classes("package p; public class C { }")
 109                 .classes("package q; public class D { }")
 110                 .write(src);
 111 
 112         javadoc("-d", base.resolve("out").toString(),
 113                 "-quiet",
 114                 "-noindex",
 115                 "--module-source-path", src.toString(),
 116                 "--module", "m");
 117 
 118         checkExit(Exit.OK);
 119         checkCaption("m", TabKind.EXPORTS);
 120         checkTableHead("m");
 121         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 122         checkPackageRow("m", "q", "i1", null, null, "&nbsp;");
 123     }
 124 
 125     @Test















































 126     public void exportSomeQualified(Path base) throws Exception {
 127         Path src = base.resolve("src");
 128         new ModuleBuilder(tb, "m")
 129                 .comment("exports multiple packages, some qualified")
 130                 .exports("p")
 131                 .exportsTo("q", "other")
 132                 .classes("package p; public class C { }")
 133                 .classes("package q; public class D { }")
 134                 .write(src);
 135 
 136         new ModuleBuilder(tb, "other")
 137                 .comment("dummy module for target of export")
 138                 .write(src);
 139 
 140         javadoc("-d", base.resolve("out-api").toString(),
 141                 "-quiet",
 142                 "-noindex",
 143                 "--module-source-path", src.toString(),
 144                 "--module", "m,other");
 145 
 146         checkExit(Exit.OK);
 147         checkCaption("m", TabKind.EXPORTS);
 148         checkTableHead("m");
 149         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 150 
 151         javadoc("-d", base.resolve("out-all").toString(),
 152                 "-quiet",
 153                 "-noindex",
 154                 "--show-module-contents", "all",
 155                 "--module-source-path", src.toString(),
 156                 "--module", "m,other");
 157 
 158         checkExit(Exit.OK);
 159         checkCaption("m", TabKind.EXPORTS);
 160         checkTableHead("m", ColKind.EXPORTED_TO);
 161         checkPackageRow("m", "p", "i0", "All Modules", null, "&nbsp;");
 162         checkPackageRow("m", "q", "i1",
 163                 """
 164                     <a href="../other/module-summary.html">other</a>""", null, "&nbsp;");
 165     }
 166 
 167     @Test
 168     public void exportWithConcealed(Path base) throws Exception {
 169         Path src = base.resolve("src");
 170         new ModuleBuilder(tb, "m")
 171                 .comment("exports package, has concealed package")
 172                 .exports("p")
 173                 .classes("package p; public class C { }")
 174                 .classes("package q; public class D { }")
 175                 .write(src);
 176 
 177         javadoc("-d", base.resolve("out-api").toString(),
 178                 "-quiet",
 179                 "-noindex",
 180                 "--module-source-path", src.toString(),
 181                 "--module", "m");
 182 
 183         checkExit(Exit.OK);
 184         checkCaption("m", TabKind.EXPORTS);
 185         checkTableHead("m");
 186         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 187 
 188         javadoc("-d", base.resolve("out-all").toString(),
 189                 "-quiet",
 190                 "-noindex",
 191                 "--show-module-contents", "all",
 192                 "--show-packages", "all",
 193                 "--module-source-path", src.toString(),
 194                 "--module", "m");
 195 
 196         checkExit(Exit.OK);
 197         checkCaption("m", TabKind.EXPORTS, TabKind.CONCEALED);
 198         checkTableHead("m", ColKind.EXPORTED_TO);
 199         checkPackageRow("m", "p", "i0", "All Modules", null, "&nbsp;");
 200         checkPackageRow("m", "q", "i1", "None", null, "&nbsp;");
 201     }
 202 
 203     @Test
 204     public void exportOpenWithConcealed(Path base) throws Exception {
 205         Path src = base.resolve("src");
 206         new ModuleBuilder(tb, "m")
 207                 .comment("exports and opens qual and unqual, with concealed")
 208                 .exports("e.all")
 209                 .exportsTo("e.other", "other")
 210                 .opens("o.all")
 211                 .opensTo("o.other", "other")
 212                 .exports("eo")
 213                 .opens("eo")
 214                 .classes("package e.all; public class CEAll { }")
 215                 .classes("package e.other; public class CEOther { }")
 216                 .classes("package o.all; public class COAll { }")
 217                 .classes("package o.other; public class COOther { }")
 218                 .classes("package eo; public class CEO { }")
 219                 .classes("package c; public class C { }")
 220                 .write(src);
 221 
 222         new ModuleBuilder(tb, "other")
 223                 .comment("dummy module for target of export and open")
 224                 .write(src);
 225 
 226         javadoc("-d", base.resolve("out-api").toString(),
 227                 "-quiet",
 228                 "-noindex",
 229                 "--module-source-path", src.toString(),
 230                 "--module", "m,other");
 231 
 232         checkExit(Exit.OK);
 233         checkCaption("m", TabKind.EXPORTS, TabKind.OPENS);
 234         checkTableHead("m", ColKind.EXPORTED_TO, ColKind.OPENED_TO);
 235         checkPackageRow("m", "e.all", "i0", "All Modules", "None", "&nbsp;");
 236         checkPackageRow("m", "eo", "i1", "All Modules", "All Modules", "&nbsp;");
 237 
 238         javadoc("-d", base.resolve("out-all").toString(),
 239                 "-quiet",
 240                 "-noindex",
 241                 "--show-module-contents", "all",
 242                 "--show-packages", "all",
 243                 "--module-source-path", src.toString(),
 244                 "--module", "m,other");
 245 
 246         checkExit(Exit.OK);
 247         checkCaption("m", TabKind.EXPORTS, TabKind.OPENS, TabKind.CONCEALED);
 248         checkTableHead("m", ColKind.EXPORTED_TO, ColKind.OPENED_TO);
 249         checkPackageRow("m", "c", "i0", "None", "None", "&nbsp;");
 250         checkPackageRow("m", "e.all", "i1", "All Modules", "None", "&nbsp;");
 251         checkPackageRow("m", "e.other", "i2",
 252                 """
 253                     <a href="../other/module-summary.html">other</a>""", "None", "&nbsp;");
 254         checkPackageRow("m", "eo", "i3", "All Modules", "All Modules", "&nbsp;");
 255         checkPackageRow("m", "o.all", "i4", "None", "All Modules", "&nbsp;");
 256         checkPackageRow("m", "o.other", "i5", "None",
 257                 """
 258                     <a href="../other/module-summary.html">other</a>""", "&nbsp;");
 259     }
 260 
 261     @Test
 262     public void openModule(Path base) throws Exception {
 263         Path src = base.resolve("src");
 264         new ModuleBuilder(tb, true, "m")
 265                 .comment("open module")
 266                 .classes("/** implicitly open package */ package p;")
 267                 .classes("package p; public class C { } ")
 268                 .classes("/** implicitly open package */ package q;")
 269                 .classes("package q; public class D { }")
 270                 .write(src);
 271 
 272         javadoc("-d", base.resolve("out").toString(),
 273                 "-quiet",
 274                 "-noindex",
 275                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 276                 "--module-source-path", src.toString(),
 277                 "--module", "m");
 278 
 279         checkExit(Exit.OK);
 280         checkCaption("m", TabKind.OPENS);
 281         checkTableHead("m");
 282         checkPackageRow("m", "p", "i0", null, null,
 283                 """
 284 
 285                     <div class="block">implicitly open package</div>
 286                     """);
 287         checkPackageRow("m", "q", "i1", null, null,
 288                 """
 289 
 290                     <div class="block">implicitly open package</div>
 291                     """);
 292     }
 293     @Test
 294     public void openSingle(Path base) throws Exception {
 295         Path src = base.resolve("src");
 296         new ModuleBuilder(tb, "m")
 297                 .comment("opens single package to all")
 298                 .opens("p")
 299                 .classes("package p; public class C { }")
 300                 .write(src);
 301 
 302         javadoc("-d", base.resolve("out").toString(),
 303                 "-quiet",
 304                 "-noindex",
 305                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 306                 "--module-source-path", src.toString(),
 307                 "--module", "m");
 308 
 309         checkExit(Exit.OK);
 310         checkCaption("m", TabKind.OPENS);
 311         checkTableHead("m");
 312         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 313     }
 314 
 315     @Test
 316     public void openMultiple(Path base) throws Exception {
 317         Path src = base.resolve("src");
 318         new ModuleBuilder(tb, "m")
 319                 .comment("opens multiple packages to all")
 320                 .opens("p")
 321                 .opens("q")
 322                 .classes("package p; public class C { }")
 323                 .classes("package q; public class D { }")
 324                 .write(src);
 325 
 326         javadoc("-d", base.resolve("out").toString(),
 327                 "-quiet",
 328                 "-noindex",
 329                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 330                 "--module-source-path", src.toString(),
 331                 "--module", "m");
 332 
 333         checkExit(Exit.OK);
 334         checkCaption("m", TabKind.OPENS);
 335         checkTableHead("m");
 336         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 337         checkPackageRow("m", "q", "i1", null, null, "&nbsp;");
 338     }
 339 
 340     @Test
 341     public void openSomeQualified(Path base) throws Exception {
 342         Path src = base.resolve("src");
 343         new ModuleBuilder(tb, "m")
 344                 .comment("opens multiple packages, some qualified")
 345                 .opens("p")
 346                 .opensTo("q", "other")
 347                 .classes("package p; public class C { }")
 348                 .classes("package q; public class D { }")
 349                 .write(src);
 350 
 351         new ModuleBuilder(tb, "other")
 352                 .comment("dummy module for target of export")
 353                 .write(src);
 354 
 355         javadoc("-d", base.resolve("out-api").toString(),
 356                 "-quiet",
 357                 "-noindex",
 358                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 359                 "--module-source-path", src.toString(),
 360                 "--module", "m,other");
 361 
 362         checkExit(Exit.OK);
 363         checkCaption("m", TabKind.OPENS);
 364         checkTableHead("m");
 365         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 366 
 367         javadoc("-d", base.resolve("out-all").toString(),
 368                 "-quiet",
 369                 "-noindex",
 370                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 371                 "--show-module-contents", "all",
 372                 "--module-source-path", src.toString(),
 373                 "--module", "m,other");
 374 
 375         checkExit(Exit.OK);
 376         checkCaption("m", TabKind.OPENS);
 377         checkTableHead("m", ColKind.OPENED_TO);
 378         checkPackageRow("m", "p", "i0", null, "All Modules", "&nbsp;");
 379         checkPackageRow("m", "q", "i1", null,
 380                 """
 381                     <a href="../other/module-summary.html">other</a>""", "&nbsp;");
 382     }
 383 
 384     @Test
 385     public void openWithConcealed(Path base) throws Exception {
 386         Path src = base.resolve("src");
 387         new ModuleBuilder(tb, "m")
 388                 .comment("opens package, has concealed package")
 389                 .opens("p")
 390                 .classes("package p; public class C { }")
 391                 .classes("package q; public class D { }")
 392                 .write(src);
 393 
 394         javadoc("-d", base.resolve("out-api").toString(),
 395                 "-quiet",
 396                 "-noindex",
 397                 "--show-packages", "all",  // required, to show open packages; see JDK-8193107
 398                 "--module-source-path", src.toString(),
 399                 "--module", "m");
 400 
 401         checkExit(Exit.OK);
 402         checkCaption("m", TabKind.OPENS);
 403         checkTableHead("m");
 404         checkPackageRow("m", "p", "i0", null, null, "&nbsp;");
 405 
 406         javadoc("-d", base.resolve("out-all").toString(),
 407                 "-quiet",
 408                 "-noindex",
 409                 "--show-module-contents", "all",
 410                 "--show-packages", "all",
 411                 "--module-source-path", src.toString(),
 412                 "--module", "m");
 413 
 414         checkExit(Exit.OK);
 415         checkCaption("m", TabKind.OPENS, TabKind.CONCEALED);
 416         checkTableHead("m", ColKind.OPENED_TO);
 417         checkPackageRow("m", "p", "i0", null, "All Modules", "&nbsp;");
 418         checkPackageRow("m", "q", "i1", null, "None", "&nbsp;");
 419     }
 420 
 421 
 422     private void checkCaption(String moduleName, TabKind... kinds) {
 423         String expect;
 424         if (kinds.length > 1) {
 425             Set<TabKind> kindSet = Set.of(kinds);
 426             StringBuilder sb = new StringBuilder();
 427             sb.append("""
 428                 <div class="table-tabs" role="tablist" aria-orientation="horizontal"><button rol\
 429                 e="tab" aria-selected="true" aria-controls="package-summary-table.tabpanel" tabi\
 430                 ndex="0" onkeydown="switchTab(event)" id="t0" class="active-table-tab">All Packa\
 431                 ges</button>""");
 432             if (kindSet.contains(TabKind.EXPORTS)) {
 433                 sb.append("""
 434                     <button role="tab" aria-selected="false" aria-controls="package-summary-table.ta\
 435                     bpanel" tabindex="-1" onkeydown="switchTab(event)" id="t1" class="table-tab" onc\
 436                     lick="show(1);">Exports</button>""");
 437             }
 438             if (kindSet.contains(TabKind.OPENS)) {
 439                 sb.append("""
 440                     <button role="tab" aria-selected="false" aria-controls="package-summary-table.ta\
 441                     bpanel" tabindex="-1" onkeydown="switchTab(event)" id="t2" class="table-tab" onc\
 442                     lick="show(2);">Opens</button>""");
 443             }
 444             if (kindSet.contains(TabKind.CONCEALED)) {
 445                 sb.append("""
 446                     <button role="tab" aria-selected="false" aria-controls="package-summary-table.ta\
 447                     bpanel" tabindex="-1" onkeydown="switchTab(event)" id="t3" class="table-tab" onc\
 448                     lick="show(4);">Concealed</button>""");
 449             }
 450             sb.append("</div>");
 451             expect = sb.toString();
 452         } else {
 453             TabKind k = kinds[0];
 454             String name = k.toString().charAt(0) + k.toString().substring(1).toLowerCase();
 455             expect = "<caption><span>" + name + "</span></caption>";
 456         }
 457 
 458         checkOutput(moduleName + "/module-summary.html", true, expect);
 459     }
 460 
 461 
 462     private void checkTableHead(String moduleName, ColKind... kinds) {
 463         Set<ColKind> kindSet = Set.of(kinds);
 464         StringBuilder sb = new StringBuilder();
 465         sb.append("""
 466             <tr>
 467             <th class="col-first" scope="col">Package</th>
 468             """);
 469         if (kindSet.contains(ColKind.EXPORTED_TO)) {
 470             sb.append("""
 471                 <th class="col-second" scope="col">Exported To Modules</th>
 472                 """);
 473         }
 474         if (kindSet.contains(ColKind.OPENED_TO)) {
 475             sb.append("""
 476                 <th class="col-second" scope="col">Opened To Modules</th>
 477                 """);
 478         }
 479         sb.append("""
 480             <th class="col-last" scope="col">Description</th>
 481             </tr>""");
 482 
 483         checkOutput(moduleName + "/module-summary.html", true, sb.toString());
 484     }
 485 
 486     private void checkPackageRow(String moduleName, String packageName,
 487             String id, String exportedTo, String openedTo, String desc) {
 488         StringBuilder sb = new StringBuilder();
 489         int idNum = Integer.parseInt(id.substring(1));
 490         String color = (idNum % 2 == 1 ? "row-color" : "alt-color");
 491         sb.append("<tr class=\"" + color + "\" id=\"" + id + """
 492             ">
 493             <th class="col-first" scope="row"><a href=\"""" + packageName.replace('.', '/') + "/package-summary.html\">"
 494                 + packageName + "</a></th>\n");
 495         if (exportedTo != null) {
 496             sb.append("<td class=\"col-second\">" + exportedTo + "</td>\n");
 497         }
 498         if (openedTo != null) {
 499             sb.append("<td class=\"col-second\">" + openedTo + "</td>\n");
 500         }
 501         sb.append("<td class=\"col-last\">" + desc + "</td>");
 502 
 503         checkOutput(moduleName + "/module-summary.html", true, sb.toString());
 504     }
 505 
 506 }
 507 
--- EOF ---