1 /* 2 * Copyright (c) 2019, 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 8178982 8220497 8210683 8241982 27 * @summary Test the search feature of javadoc. 28 * @library ../../lib 29 * @library /test/lib 30 * @modules jdk.javadoc/jdk.javadoc.internal.tool 31 * @build javadoc.tester.* 32 * @build jtreg.SkippedException 33 * @run main TestSearchScript 34 */ 35 36 import javadoc.tester.JavadocTester; 37 38 import javax.script.Bindings; 39 import javax.script.Invocable; 40 import javax.script.ScriptContext; 41 import javax.script.ScriptEngine; 42 import javax.script.ScriptEngineManager; 43 import javax.script.ScriptException; 44 import java.io.BufferedReader; 45 import java.io.File; 46 import java.io.FileReader; 47 import java.io.IOException; 48 import java.util.List; 49 50 import jtreg.SkippedException; 51 52 /* 53 * Tests for the search feature using any available javax.script JavaScript engine. 54 * The test is skipped if no JavaScript engine is available. 55 */ 56 public class TestSearchScript extends JavadocTester { 57 main(String... args)58 public static void main(String... args) throws Exception { 59 TestSearchScript tester = new TestSearchScript(); 60 tester.runTests(); 61 } 62 getEngine()63 private Invocable getEngine() throws ScriptException, IOException, NoSuchMethodException { 64 ScriptEngineManager engineManager = new ScriptEngineManager(); 65 // Use "js" engine name to use any available JavaScript engine. 66 ScriptEngine engine = engineManager.getEngineByName("js"); 67 if (engine == null) { 68 throw new SkippedException("JavaScript engine is not available."); 69 } 70 // For GraalJS set Nashorn compatibility mode via Bindings, 71 // see https://github.com/graalvm/graaljs/blob/master/docs/user/ScriptEngine.md 72 Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); 73 bindings.put("polyglot.js.nashorn-compat", true); 74 engine.eval(new BufferedReader(new FileReader(new File(testSrc, "javadoc-search.js")))); 75 Invocable inv = (Invocable) engine; 76 inv.invokeFunction("loadIndexFiles", outputDir.getAbsolutePath()); 77 return inv; 78 } 79 80 @Test testModuleSearch()81 public void testModuleSearch() throws ScriptException, IOException, NoSuchMethodException { 82 javadoc("-d", "out-full", 83 "-Xdoclint:none", 84 "-use", 85 "--module-source-path", testSrc, 86 "--module", "mapmodule", 87 "mappkg", "mappkg.impl"); 88 checkExit(Exit.OK); 89 90 Invocable inv = getEngine(); 91 92 // exact match, case sensitivity 93 checkSearch(inv, "mapmodule", List.of("mapmodule")); 94 checkSearch(inv, "mappkg", List.of("mapmodule/mappkg", "mapmodule/mappkg.impl", "mappkg.system.property")); 95 checkSearch(inv, "Mapmodule", List.of("mapmodule")); 96 checkSearch(inv, "Mappkg", List.of("mapmodule/mappkg", "mapmodule/mappkg.impl", "mappkg.system.property")); 97 checkSearch(inv, "mymap", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 98 checkSearch(inv, "MyMap", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 99 checkSearch(inv, "mymap(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 100 checkSearch(inv, "MyMap(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 101 checkSearch(inv, "mymap()", List.of("mappkg.impl.MyMap.MyMap()")); 102 checkSearch(inv, "MyMap()", List.of("mappkg.impl.MyMap.MyMap()")); 103 checkSearch(inv, "Mymap", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 104 checkSearch(inv, "Mymap()", List.of("mappkg.impl.MyMap.MyMap()")); 105 106 // left boundaries, ranking 107 checkSearch(inv, "map", List.of("mapmodule", "mapmodule/mappkg", "mapmodule/mappkg.impl", "mappkg.Map", "mappkg.impl.MyMap", 108 "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)", "mappkg.system.property")); 109 checkSearch(inv, "Map", List.of("mapmodule", "mapmodule/mappkg", "mapmodule/mappkg.impl", "mappkg.Map", "mappkg.impl.MyMap", 110 "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)", "mappkg.system.property")); 111 checkSearch(inv, "MAP", List.of("mapmodule", "mapmodule/mappkg", "mapmodule/mappkg.impl", "mappkg.Map", "mappkg.impl.MyMap", 112 "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)", "mappkg.system.property")); 113 checkSearch(inv, "value", List.of("mappkg.impl.MyMap.OTHER_VALUE", "mappkg.impl.MyMap.some_value")); 114 checkSearch(inv, "VALUE", List.of("mappkg.impl.MyMap.OTHER_VALUE", "mappkg.impl.MyMap.some_value")); 115 checkSearch(inv, "map.other", List.of("mappkg.impl.MyMap.OTHER_VALUE")); 116 checkSearch(inv, "Map.Some_", List.of("mappkg.impl.MyMap.some_value")); 117 118 checkSearch(inv, "Mm", List.of()); 119 checkSearch(inv, "mym", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 120 checkSearch(inv, "imp.mym.mym(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 121 checkSearch(inv, "imp.mym.mym(m", List.of("mappkg.impl.MyMap.MyMap(Map)")); 122 123 // camel case 124 checkSearch(inv, "MM", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 125 checkSearch(inv, "MyM", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 126 checkSearch(inv, "Mym", List.of("mappkg.impl.MyMap", "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 127 checkSearch(inv, "i.MyM.MyM(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 128 checkSearch(inv, "i.MMa.MMa(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 129 checkSearch(inv, "i.MyM.MyM(Ma", List.of("mappkg.impl.MyMap.MyMap(Map)")); 130 checkSearch(inv, "i.MMa.MMa(M", List.of("mappkg.impl.MyMap.MyMap(Map)")); 131 checkSearch(inv, "i.Mym.MyM(", List.of("mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)")); 132 checkSearch(inv, "i.Mym.Ma(", List.of()); 133 134 checkSearch(inv, "mapm", List.of("mapmodule")); 135 136 // child entity listing 137 checkSearch(inv, "mapmodule/", List.of("mapmodule/mappkg", "mapmodule/mappkg.impl")); 138 checkSearch(inv, "mapmod/", List.of("mapmodule/mappkg", "mapmodule/mappkg.impl")); 139 checkSearch(inv, "module/", List.of()); 140 checkSearch(inv, "le/", List.of()); 141 checkSearch(inv, "mapmodule.", List.of()); 142 checkSearch(inv, "mapmod.", List.of()); 143 checkSearch(inv, "mappkg.", List.of("mapmodule/mappkg.impl", "mappkg.Map", "mappkg.system.property")); 144 checkSearch(inv, "mappkg.", List.of("mapmodule/mappkg.impl", "mappkg.Map", "mappkg.system.property")); 145 checkSearch(inv, "Map.", List.of("mapmodule/mappkg.impl", "mappkg.Map", "mappkg.Map.contains(Object)", 146 "mappkg.Map.get(Object)", "mappkg.Map.iterate()", "mappkg.Map.put(Object, Object)", 147 "mappkg.Map.remove(Object)", "mappkg.impl.MyMap.contains(Object)", 148 "mappkg.impl.MyMap.get(Object)", "mappkg.impl.MyMap.iterate()", 149 "mappkg.impl.MyMap.MyMap()", "mappkg.impl.MyMap.MyMap(Map)", 150 "mappkg.impl.MyMap.OTHER_VALUE", "mappkg.impl.MyMap.put(Object, Object)", 151 "mappkg.impl.MyMap.remove(Object)", "mappkg.impl.MyMap.some_value", 152 "mappkg.system.property")); 153 checkSearch(inv, "mym.", List.of("mappkg.impl.MyMap.contains(Object)", "mappkg.impl.MyMap.get(Object)", 154 "mappkg.impl.MyMap.iterate()", "mappkg.impl.MyMap.MyMap()", 155 "mappkg.impl.MyMap.MyMap(Map)", "mappkg.impl.MyMap.OTHER_VALUE", 156 "mappkg.impl.MyMap.put(Object, Object)", "mappkg.impl.MyMap.remove(Object)", 157 "mappkg.impl.MyMap.some_value")); 158 checkSearch(inv, "MyMap.i", List.of("mappkg.impl.MyMap.iterate()")); 159 160 // system properties 161 checkSearch(inv, "mappkg.system.property", List.of("mappkg.system.property")); 162 checkSearch(inv, "system.property", List.of("mappkg.system.property")); 163 checkSearch(inv, "property", List.of("mappkg.system.property")); 164 checkSearch(inv, "sys.prop", List.of("mappkg.system.property")); 165 checkSearch(inv, "m.s.p", List.of("mappkg.system.property")); 166 checkSearch(inv, "operty", List.of()); 167 168 // search tag 169 checkSearch(inv, "search tag", List.of("search tag", "multiline search tag")); 170 checkSearch(inv, "search tag", List.of("search tag", "multiline search tag")); 171 checkSearch(inv, "search ", List.of("multiline search tag", "search tag")); 172 checkSearch(inv, "tag", List.of("multiline search tag", "search tag")); 173 checkSearch(inv, "sea", List.of("multiline search tag", "search tag")); 174 checkSearch(inv, "multi", List.of("multiline search tag")); 175 checkSearch(inv, "ear", List.of()); 176 } 177 178 179 @Test testPackageSource()180 public void testPackageSource() throws ScriptException, IOException, NoSuchMethodException { 181 javadoc("-d", "out-overload", 182 "-Xdoclint:none", 183 "-use", 184 "-sourcepath", testSrc, 185 "listpkg"); 186 checkExit(Exit.OK); 187 188 Invocable inv = getEngine(); 189 190 // exact match, case sensitvity, left boundaries 191 checkSearch(inv, "list", List.of("listpkg", "listpkg.List", "listpkg.ListProvider", "listpkg.MyList", 192 "listpkg.MyListFactory", "listpkg.ListProvider.ListProvider()", 193 "listpkg.MyListFactory.createList(ListProvider, MyListFactory)", 194 "listpkg.ListProvider.makeNewList()", 195 "listpkg.MyList.MyList()", "listpkg.MyListFactory.MyListFactory()")); 196 checkSearch(inv, "List", List.of("listpkg", "listpkg.List", "listpkg.ListProvider", "listpkg.MyList", 197 "listpkg.MyListFactory", "listpkg.ListProvider.ListProvider()", 198 "listpkg.MyListFactory.createList(ListProvider, MyListFactory)", 199 "listpkg.ListProvider.makeNewList()", 200 "listpkg.MyList.MyList()", "listpkg.MyListFactory.MyListFactory()")); 201 // partial match 202 checkSearch(inv, "fact", List.of("listpkg.MyListFactory", "listpkg.MyListFactory.MyListFactory()")); 203 checkSearch(inv, "pro", List.of("listpkg.ListProvider", "listpkg.ListProvider.ListProvider()")); 204 checkSearch(inv, "listpro", List.of("listpkg.ListProvider", "listpkg.ListProvider.ListProvider()")); 205 206 // camel case 207 checkSearch(inv, "l.MLF.cL(LP, MLF)", List.of("listpkg.MyListFactory.createList(ListProvider, MyListFactory)")); 208 checkSearch(inv, "Fact.creaLi(LiPro,MLiFact)", List.of("listpkg.MyListFactory.createList(ListProvider, MyListFactory)")); 209 checkSearch(inv, "(LP,ML", List.of("listpkg.MyListFactory.createList(ListProvider, MyListFactory)")); 210 211 // ranking of overloaded methods JDK-8210683 212 checkSearch(inv, "list.of", 213 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 214 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 215 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 216 checkSearch(inv, "Li.of", 217 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 218 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 219 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 220 checkSearch(inv, "li.Li.o", 221 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 222 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 223 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 224 checkSearch(inv, "l.l.o", 225 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 226 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 227 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 228 checkSearch(inv, "L.l.o", List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 229 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", "listpkg.List.of(E, E, E, E, E)", 230 "listpkg.List.of(E...)")); 231 232 // whitespace 233 checkSearch(inv, "(e,e,e", 234 List.of("listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 235 "listpkg.List.of(E, E, E, E, E)")); 236 checkSearch(inv, "(e, e,e", 237 List.of("listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 238 "listpkg.List.of(E, E, E, E, E)")); 239 checkSearch(inv, "(e, e, e", 240 List.of("listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 241 "listpkg.List.of(E, E, E, E, E)")); 242 checkSearch(inv, "(e, e, e", 243 List.of("listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 244 "listpkg.List.of(E, E, E, E, E)")); 245 checkSearch(inv, "(e, e, e ,", 246 List.of("listpkg.List.of(E, E, E, E)", "listpkg.List.of(E, E, E, E, E)")); 247 checkSearch(inv, "(e , e, e,", 248 List.of("listpkg.List.of(E, E, E, E)", "listpkg.List.of(E, E, E, E, E)")); 249 checkSearch(inv, " listpkg .list .of ", 250 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 251 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 252 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 253 checkSearch(inv, " l. l. o", 254 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 255 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 256 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 257 checkSearch(inv, "list . of", 258 List.of("listpkg.List.of()", "listpkg.List.of(E)", "listpkg.List.of(E, E)", 259 "listpkg.List.of(E, E, E)", "listpkg.List.of(E, E, E, E)", 260 "listpkg.List.of(E, E, E, E, E)", "listpkg.List.of(E...)")); 261 checkSearch(inv, "lis t.of", List.of()); 262 checkSearch(inv, "list . of(e,e,e,", 263 List.of("listpkg.List.of(E, E, E, E)", "listpkg.List.of(E, E, E, E, E)")); 264 checkSearch(inv, "l . o (e,e,e,", 265 List.of("listpkg.List.of(E, E, E, E)", "listpkg.List.of(E, E, E, E, E)")); 266 checkSearch(inv, "search \tt", List.of("other search tag")); 267 checkSearch(inv, "sear ch", List.of()); 268 checkSearch(inv, "( e ..", List.of("listpkg.List.of(E...)")); 269 checkSearch(inv, "( i [ ]", List.of("listpkg.Nolist.withArrayArg(int[])")); 270 271 // empty/white space search should not trigger results 272 checkNullSearch(inv, ""); 273 checkNullSearch(inv, " "); 274 checkNullSearch(inv, " "); 275 checkNullSearch(inv, " \t\t "); 276 277 278 // _ word boundaries and case sensitivity 279 checkSearch(inv, "some", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 280 checkSearch(inv, "SOME", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 281 checkSearch(inv, "Some", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 282 checkSearch(inv, "int", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 283 checkSearch(inv, "INT", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 284 checkSearch(inv, "Int", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 285 checkSearch(inv, "int_con", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 286 checkSearch(inv, "INT_CON", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 287 checkSearch(inv, "NT", List.of()); 288 checkSearch(inv, "NT_", List.of()); 289 checkSearch(inv, "_const", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 290 checkSearch(inv, "_CONST", List.of("listpkg.Nolist.SOME_INT_CONSTANT")); 291 292 // Test for all packages, all classes links 293 checkSearch(inv, "all", List.of("All Packages", "All Classes")); 294 checkSearch(inv, "All", List.of("All Packages", "All Classes")); 295 checkSearch(inv, "ALL", List.of("All Packages", "All Classes")); 296 297 // test for generic types, var-arg and array args 298 checkSearch(inv, "(map<string, ? ext collection>)", 299 List.of("listpkg.Nolist.withTypeParams(Map<String, ? extends Collection>)")); 300 checkSearch(inv, "(m<str,? ext coll>", 301 List.of("listpkg.Nolist.withTypeParams(Map<String, ? extends Collection>)")); 302 checkSearch(inv, "(object...", List.of("listpkg.Nolist.withVarArgs(Object...)")); 303 checkSearch(inv, "(obj...", List.of("listpkg.Nolist.withVarArgs(Object...)")); 304 checkSearch(inv, "(e..", List.of("listpkg.List.of(E...)")); 305 checkSearch(inv, "(int[]", List.of("listpkg.Nolist.withArrayArg(int[])")); 306 checkSearch(inv, "(i[]", List.of("listpkg.Nolist.withArrayArg(int[])")); 307 } 308 checkSearch(Invocable inv, String query, List<String> results)309 void checkSearch(Invocable inv, String query, List<String> results) throws ScriptException, NoSuchMethodException { 310 checkList((List) inv.invokeFunction("search", query), results); 311 } 312 checkList(List<?> result, List<?> expected)313 void checkList(List<?> result, List<?> expected) { 314 checking("Checking list: " + result); 315 if (!expected.equals(result)) { 316 failed("Expected: " + expected + ", got: " + result); 317 } else { 318 passed("List matches expected result"); 319 } 320 } 321 checkNullSearch(Invocable inv, String query)322 void checkNullSearch(Invocable inv, String query) throws ScriptException, NoSuchMethodException { 323 Object result = inv.invokeFunction("search", query); 324 checking("Checking null result"); 325 if (result == null) { 326 passed("Result is null as expected"); 327 } else { 328 failed("Expected: null, got: " + result); 329 } 330 } 331 } 332