1 /*
   2  * Copyright (c) 2014, 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  * @test
  26  * @bug 8039410 8042601 8042829 8049393 8050031
  27  * @summary test to determine if members are ordered correctly
  28  * @author ksrini
  29  * @library ../lib/
  30  * @modules jdk.javadoc
  31  * @build JavadocTester
  32  * @run main TestOrdering
  33  */
  34 
  35 import java.io.File;
  36 import java.io.IOException;
  37 import java.nio.file.Files;
  38 import java.util.ArrayList;
  39 import java.util.Arrays;
  40 import java.util.Collections;
  41 import java.util.List;
  42 
  43 import static java.nio.file.StandardOpenOption.*;
  44 
  45 public class TestOrdering extends JavadocTester {
  46 
  47     public static void main(String[] args) throws Exception {
  48         TestOrdering tester = new TestOrdering();
  49         tester.runTests();
  50     }
  51 
  52     @Test
  53     void testUnnamedPackagesForClassUse() {
  54         javadoc("-d", "out",
  55                 "-sourcepath", testSrc,
  56                 "-use",
  57                 testSrc("C.java"), testSrc("UsedInC.java"));
  58         checkExit(Exit.OK);
  59         checkExecutableMemberOrdering("class-use/UsedInC.html");
  60     }
  61 
  62     @Test
  63     void testNamedPackagesForClassUse() {
  64         javadoc("-d", "out-1",
  65                 "-sourcepath", testSrc,
  66                 "-use",
  67                 "pkg1");
  68         checkExit(Exit.OK);
  69         checkClassUseOrdering("pkg1/class-use/UsedClass.html");
  70         checkOrder("pkg1/class-use/UsedClass.html", expectedClassUseMethodOrdering);
  71         checkOrder("pkg1/class-use/UsedClass.html", expectedClassUseWithTypeParams);
  72         checkOrder("pkg1/class-use/UsedClass.html", expectedInnerClassContructors);
  73     }
  74 
  75     enum ListOrder { NONE, REVERSE, SHUFFLE };
  76     /*
  77      * By default we do not shuffle the input list, in order to keep the list deterministic,
  78      * and the test predictable. However, we can turn on the stress mode, by setting the following
  79      * property if required.
  80      */
  81     static final ListOrder STRESS_MODE = Boolean.getBoolean("TestOrder.STRESS")
  82             ? ListOrder.SHUFFLE
  83             : ListOrder.REVERSE;
  84 
  85     /*
  86      * Controls the number of sibling packages,  pkg0, pkg1, pkg2, .....
  87      */
  88     static final int MAX_PACKAGES = 4;
  89 
  90     /*
  91      * Controls the number of children packages, pkg0, pkg0.pkg, pkg0.pkg.pkg, .....
  92      * Note: having too long a depth (> 256 chars on Windows), will likely lead to
  93      * cause problems with automated build and test systems.
  94      */
  95     static final int MAX_SUBPACKAGES_DEPTH = 4;
  96     @Test
  97     void testIndexOrdering() throws IOException {
  98         final String clsname = "Add";
  99         List<String> cmdArgs = new ArrayList();
 100         cmdArgs.add("-d");
 101         cmdArgs.add("out-2");
 102         cmdArgs.add("-sourcepath");
 103         cmdArgs.add("src");
 104         cmdArgs.add("-package");
 105         System.out.println("STRESS_MODE: " + STRESS_MODE);
 106         emitFile(null, clsname, STRESS_MODE);
 107         for (int width = 0 ; width < MAX_PACKAGES ; width++) {
 108             String wpkgname = "add" + width;
 109             String dpkgname = wpkgname;
 110             emitFile(wpkgname, clsname, ListOrder.NONE); // list as-is
 111             cmdArgs.add(wpkgname);
 112             for (int depth = 1 ; depth < MAX_SUBPACKAGES_DEPTH ; depth++) {
 113                 dpkgname = dpkgname + ".add";
 114                 emitFile(dpkgname, clsname, STRESS_MODE);
 115                 cmdArgs.add(dpkgname);
 116             }
 117         }
 118         File srcDir = new File(new File("."), "src");
 119         cmdArgs.add(new File(srcDir, clsname + ".java").getPath());
 120         javadoc(cmdArgs.toArray(new String[cmdArgs.size()]));
 121         checkExit(Exit.OK);
 122         checkOrder("index-all.html", composeTestVectors());
 123         checkOrder("add0/add/package-tree.html", expectedPackageTreeOrdering);
 124         checkOrder("overview-tree.html", expectedOverviewOrdering);
 125     }
 126 
 127     @Test
 128     void testIndexTypeClustering() {
 129         javadoc("-d", "out-3",
 130                 "-sourcepath", testSrc("src-2"),
 131                 "-use",
 132                 "a",
 133                 "b",
 134                 "e",
 135                 "something");
 136         checkOrder("index-all.html", typeTestVectors);
 137         checkExit(Exit.OK);
 138     }
 139     String[] typeTestVectors = {
 140         "something</a> - package something</dt>",
 141         "something</span></a> - Class in",
 142         "something</span></a> - Enum in",
 143         "something</span></a> - Interface in",
 144         "something</span></a> - Annotation Type in",
 145         "something</a></span> - Variable in class",
 146         "something()</a></span> - Constructor",
 147         "something()</a></span> - Method in class a.<a href=\"a/A.html\"",
 148         "something()</a></span> - Method in class a.<a href=\"a/something.html\"",
 149         "something()</a></span> - Method in class something.<a href=\"something/J.html\""
 150     };
 151     String[] composeTestVectors() {
 152         List<String> testList = new ArrayList<>();
 153 
 154         for (String x : expectedMethodOrdering) {
 155             testList.add(x);
 156             for (int i = 0; i < MAX_PACKAGES; i++) {
 157                 String wpkg = "add" + i;
 158                 testList.add(wpkg + "/" + x);
 159                 String dpkg = wpkg;
 160                 for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) {
 161                     dpkg = dpkg + "/" + "add";
 162                     testList.add(dpkg + "/" + x);
 163                 }
 164             }
 165         }
 166         for (String x : expectedEnumOrdering) {
 167             testList.add(x.replace("REPLACE_ME", "&lt;Unnamed&gt;"));
 168             for (int i = 0; i < MAX_PACKAGES; i++) {
 169                 String wpkg = "add" + i;
 170                 testList.add(wpkg + "/" + x.replace("REPLACE_ME", wpkg));
 171                 String dpkg = wpkg;
 172                 for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) {
 173                     dpkg = dpkg + "/" + "add";
 174                     testList.add(dpkg + "/" + x.replace("REPLACE_ME", pathToPackage(dpkg)));
 175                 }
 176             }
 177         }
 178         testList.addAll(Arrays.asList(expectedFieldOrdering));
 179         return testList.toArray(new String[testList.size()]);
 180     }
 181     void checkExecutableMemberOrdering(String usePage) {
 182         String contents = readFile(usePage);
 183         // check constructors
 184         checking("constructors");
 185         int idx1 = contents.indexOf("C.html#C-UsedInC");
 186         int idx2 = contents.indexOf("C.html#C-UsedInC-int");
 187         int idx3 = contents.indexOf("C.html#C-UsedInC-java.lang.String");
 188         if (idx1 == -1 || idx2 == -1 || idx3 == -1) {
 189             failed("ctor strings not found");
 190         } else if (idx1 > idx2 || idx2 > idx3 || idx1 > idx3) {
 191             failed("ctor strings are out of order");
 192         } else
 193             passed("ctor strings are in order");
 194 
 195         // check methods
 196         checking("methods");
 197         idx1 = contents.indexOf("C.html#ymethod-int");
 198         idx2 = contents.indexOf("C.html#ymethod-java.lang.String");
 199         if (idx1 == -1 || idx2 == -1) {
 200             failed("#ymethod strings not found");
 201         } else if (idx1 > idx2) {
 202             failed("#ymethod strings are out of order");
 203         } else
 204             passed("Executable Member Ordering: OK");
 205     }
 206 
 207     void checkClassUseOrdering(String usePage) {
 208         checkClassUseOrdering(usePage, "pkg1/C#ITERATION#.html#zfield");
 209         checkClassUseOrdering(usePage, "pkg1/C#ITERATION#.html#fieldInC#ITERATION#");
 210         checkClassUseOrdering(usePage, "pkg1/C#ITERATION#.html#zmethod-pkg1.UsedClass");
 211         checkClassUseOrdering(usePage, "pkg1/C#ITERATION#.html#methodInC#ITERATION#");
 212     }
 213 
 214     void checkClassUseOrdering(String usePage, String searchString) {
 215         String contents = readFile(usePage);
 216         int lastidx = 0;
 217         System.out.println("testing for " + searchString);
 218         for (int i = 1; i < 5; i++) {
 219             String s = searchString.replaceAll("#ITERATION#", Integer.toString(i));
 220             checking(s);
 221             int idx = contents.indexOf(s);
 222             if (idx < lastidx) {
 223                 failed(s + ", member ordering error, last:" + lastidx + ", got:" + idx);
 224             } else {
 225                 passed("\tlast: " + lastidx + " got:" + idx);
 226             }
 227             lastidx = idx;
 228         }
 229     }
 230 
 231     static String[] contents = {
 232         "public add ADDADD;",
 233         "public add AddAdd;",
 234         "public add addadd;",
 235         "public enum add {add, ADD, addd, ADDD};",
 236         "public enum ADD {ADD, add, addd, ADDD};",
 237         "public void   add(){}",
 238         "public void   add(double d){}",
 239         "public void   add(int i, float f){}",
 240         "public void   add(float f, int i){}",
 241         "public void   add(double d, byte b){}",
 242         "public Double add(Double d) {return (double) 22/7;}",
 243         "public double add(double d1, double d2) {return d1 + d2;}",
 244         "public double add(double d1, Double  d2) {return d1 + d2;}",
 245         "public Float  add(float f) {return (float) 22/7;}",
 246         "public void   add(int i){}",
 247         "public int    add(Integer i) {return 0;}"
 248     };
 249 
 250     void emitFile(String pkgname, String clsname, ListOrder order) throws IOException {
 251         File srcDir = new File("src");
 252         File outDir = pkgname == null
 253             ? srcDir
 254             : new File(srcDir, pkgname.replace(".", File.separator));
 255         File outFile = new File(outDir, clsname + ".java");
 256         outDir.mkdirs();
 257         List<String> scratch = new ArrayList<>(Arrays.asList(contents));
 258         switch (order) {
 259             case SHUFFLE:
 260                 Collections.shuffle(scratch);
 261                 break;
 262             case REVERSE:
 263                 Collections.reverse(scratch);
 264                 break;
 265             default:
 266                 // leave list as-is
 267         }
 268         // insert the header
 269         scratch.add(0, "public class " + clsname + " {");
 270         if (pkgname != null) {
 271             scratch.add(0, "package " + pkgname + ";");
 272         }
 273         // append the footer
 274         scratch.add("}");
 275         Files.write(outFile.toPath(), scratch, CREATE, TRUNCATE_EXISTING);
 276     }
 277 
 278     String pathToPackage(String in) {
 279         return in.replace("/", ".");
 280     }
 281 
 282     final String expectedInnerClassContructors[] = {
 283         "../../pkg1/A.html#A-pkg1.UsedClass-",
 284         "../../pkg1/B.A.html#A-pkg1.UsedClass-",
 285         "../../pkg1/B.html#B-pkg1.UsedClass-",
 286         "../../pkg1/A.C.html#C-pkg1.UsedClass-java.lang.Object:A-",
 287         "../../pkg1/A.C.html#C-pkg1.UsedClass-java.util.Collection-",
 288         "../../pkg1/A.C.html#C-pkg1.UsedClass-java.util.List-"
 289     };
 290 
 291     final String expectedClassUseMethodOrdering[] = {
 292         "../../pkg1/MethodOrder.html#m--",
 293         "../../pkg1/MethodOrder.html#m-byte:A-",
 294         "../../pkg1/MethodOrder.html#m-double-",
 295         "../../pkg1/MethodOrder.html#m-double-double-",
 296         "../../pkg1/MethodOrder.html#m-double-java.lang.Double-",
 297         "../../pkg1/MethodOrder.html#m-int-",
 298         "../../pkg1/MethodOrder.html#m-int-int-",
 299         "../../pkg1/MethodOrder.html#m-int-java.lang.Integer-",
 300         "../../pkg1/MethodOrder.html#m-java.lang.Double-",
 301         "../../pkg1/MethodOrder.html#m-java.lang.Double-double-",
 302         "../../pkg1/MethodOrder.html#m-java.lang.Double-java.lang.Double-",
 303         "../../pkg1/MethodOrder.html#m-java.lang.Integer-",
 304         "../../pkg1/MethodOrder.html#m-java.lang.Integer-int-",
 305         "../../pkg1/MethodOrder.html#m-java.lang.Integer-java.lang.Integer-",
 306         "../../pkg1/MethodOrder.html#m-java.lang.Object:A-",
 307         "../../pkg1/MethodOrder.html#m-java.util.ArrayList-",
 308         "../../pkg1/MethodOrder.html#m-java.util.Collection-",
 309         "../../pkg1/MethodOrder.html#m-java.util.List-"
 310     };
 311     final String expectedClassUseWithTypeParams[] = {
 312         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-",
 313         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass-",
 314         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass:A-",
 315         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-java.lang.String-"
 316     };
 317     final String expectedMethodOrdering[] = {
 318         "Add.html#add--",
 319         "Add.html#add-double-",
 320         "Add.html#add-double-byte-",
 321         "Add.html#add-double-double-",
 322         "Add.html#add-double-java.lang.Double-",
 323         "Add.html#add-float-",
 324         "Add.html#add-float-int-",
 325         "Add.html#add-int-",
 326         "Add.html#add-int-float-",
 327         "Add.html#add-java.lang.Double-",
 328         "Add.html#add-java.lang.Integer-"
 329     };
 330     final String expectedEnumOrdering[] = {
 331         "Add.add.html\" title=\"enum in REPLACE_ME\"",
 332         "Add.ADD.html\" title=\"enum in REPLACE_ME\""
 333     };
 334     final String expectedFieldOrdering[] = {
 335         "Add.html#addadd\"",
 336         "add0/add/add/add/Add.html#addadd\"",
 337         "add0/add/add/Add.html#addadd\"",
 338         "add0/add/Add.html#addadd\"",
 339         "add0/Add.html#addadd\"",
 340         "add1/add/add/add/Add.html#addadd\"",
 341         "add1/add/add/Add.html#addadd\"",
 342         "add1/add/Add.html#addadd\"",
 343         "add1/Add.html#addadd\"",
 344         "add2/add/add/add/Add.html#addadd\"",
 345         "add2/add/add/Add.html#addadd\"",
 346         "add2/add/Add.html#addadd\"",
 347         "add2/Add.html#addadd\"",
 348         "add3/add/add/add/Add.html#addadd\"",
 349         "add3/add/add/Add.html#addadd\"",
 350         "add3/add/Add.html#addadd\"",
 351         "add3/Add.html#addadd\"",
 352         "Add.html#AddAdd\"",
 353         "add0/add/add/add/Add.html#AddAdd\"",
 354         "add0/add/add/Add.html#AddAdd\"",
 355         "add0/add/Add.html#AddAdd\"",
 356         "add0/Add.html#AddAdd\"",
 357         "add1/add/add/add/Add.html#AddAdd\"",
 358         "add1/add/add/Add.html#AddAdd\"",
 359         "add1/add/Add.html#AddAdd\"",
 360         "add1/Add.html#AddAdd\"",
 361         "add2/add/add/add/Add.html#AddAdd\"",
 362         "add2/add/add/Add.html#AddAdd\"",
 363         "add2/add/Add.html#AddAdd\"",
 364         "add2/Add.html#AddAdd\"",
 365         "add3/add/add/add/Add.html#AddAdd\"",
 366         "add3/add/add/Add.html#AddAdd\"",
 367         "add3/add/Add.html#AddAdd\"",
 368         "add3/Add.html#AddAdd\"",
 369         "Add.html#ADDADD\"",
 370         "add0/add/add/add/Add.html#ADDADD\"",
 371         "add0/add/add/Add.html#ADDADD\"",
 372         "add0/add/Add.html#ADDADD\"",
 373         "add0/Add.html#ADDADD\"",
 374         "add1/add/add/add/Add.html#ADDADD\"",
 375         "add1/add/add/Add.html#ADDADD\"",
 376         "add1/add/Add.html#ADDADD\"",
 377         "add1/Add.html#ADDADD\"",
 378         "add2/add/add/add/Add.html#ADDADD\"",
 379         "add2/add/add/Add.html#ADDADD\"",
 380         "add2/add/Add.html#ADDADD\"",
 381         "add2/Add.html#ADDADD\"",
 382         "add3/add/add/add/Add.html#ADDADD\"",
 383         "add3/add/add/Add.html#ADDADD\"",
 384         "add3/add/Add.html#ADDADD\"",
 385         "add3/Add.html#ADDADD\""
 386     };
 387     final String expectedPackageTreeOrdering[] = {
 388         "<a href=\"../../add0/add/Add.add.html\" title=\"enum in add0.add\">",
 389         "<a href=\"../../add0/add/Add.ADD.html\" title=\"enum in add0.add\">"
 390     };
 391     final String expectedOverviewOrdering[] = {
 392         "<a href=\"Add.add.html\" title=\"enum in &lt;Unnamed&gt;\">",
 393         "<a href=\"add0/Add.add.html\" title=\"enum in add0\">",
 394         "<a href=\"add0/add/Add.add.html\" title=\"enum in add0.add\">",
 395         "<a href=\"add0/add/add/Add.add.html\" title=\"enum in add0.add.add\">",
 396         "<a href=\"add0/add/add/add/Add.add.html\" title=\"enum in add0.add.add.add\">",
 397         "<a href=\"add1/Add.add.html\" title=\"enum in add1\">",
 398         "<a href=\"add1/add/Add.add.html\" title=\"enum in add1.add\">",
 399         "<a href=\"add1/add/add/Add.add.html\" title=\"enum in add1.add.add\">",
 400         "<a href=\"add1/add/add/add/Add.add.html\" title=\"enum in add1.add.add.add\">",
 401         "<a href=\"add2/Add.add.html\" title=\"enum in add2\">",
 402         "<a href=\"add2/add/Add.add.html\" title=\"enum in add2.add\">",
 403         "<a href=\"add2/add/add/Add.add.html\" title=\"enum in add2.add.add\">",
 404         "<a href=\"add2/add/add/add/Add.add.html\" title=\"enum in add2.add.add.add\">",
 405         "<a href=\"add3/Add.add.html\" title=\"enum in add3\">",
 406         "<a href=\"add3/add/Add.add.html\" title=\"enum in add3.add\">",
 407         "<a href=\"add3/add/add/Add.add.html\" title=\"enum in add3.add.add\">",
 408         "<a href=\"add3/add/add/add/Add.add.html\" title=\"enum in add3.add.add.add\">",
 409         "<a href=\"Add.ADD.html\" title=\"enum in &lt;Unnamed&gt;\">",
 410         "<a href=\"add0/Add.ADD.html\" title=\"enum in add0\">",
 411         "<a href=\"add0/add/Add.ADD.html\" title=\"enum in add0.add\">",
 412         "<a href=\"add0/add/add/Add.ADD.html\" title=\"enum in add0.add.add\">",
 413         "<a href=\"add0/add/add/add/Add.ADD.html\" title=\"enum in add0.add.add.add\">",
 414         "<a href=\"add1/Add.ADD.html\" title=\"enum in add1\">",
 415         "<a href=\"add1/add/Add.ADD.html\" title=\"enum in add1.add\">",
 416         "<a href=\"add1/add/add/Add.ADD.html\" title=\"enum in add1.add.add\">",
 417         "<a href=\"add1/add/add/add/Add.ADD.html\" title=\"enum in add1.add.add.add\">",
 418         "<a href=\"add2/Add.ADD.html\" title=\"enum in add2\">",
 419         "<a href=\"add2/add/Add.ADD.html\" title=\"enum in add2.add\">",
 420         "<a href=\"add2/add/add/Add.ADD.html\" title=\"enum in add2.add.add\">",
 421         "<a href=\"add2/add/add/add/Add.ADD.html\" title=\"enum in add2.add.add.add\">",
 422         "<a href=\"add3/Add.ADD.html\" title=\"enum in add3\">",
 423         "<a href=\"add3/add/Add.ADD.html\" title=\"enum in add3.add\">",
 424         "<a href=\"add3/add/add/Add.ADD.html\" title=\"enum in add3.add.add\">",
 425         "<a href=\"add3/add/add/add/Add.ADD.html\" title=\"enum in add3.add.add.add\">",
 426     };
 427 }