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", "<Unnamed>")); 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 <Unnamed>\">", 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 <Unnamed>\">", 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 }