1 /* 2 * Copyright (c) 2016, 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 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 27 * @summary Simple jshell tool tests 28 * @modules jdk.compiler/com.sun.tools.javac.api 29 * jdk.compiler/com.sun.tools.javac.main 30 * jdk.jdeps/com.sun.tools.javap 31 * jdk.jshell/jdk.internal.jshell.tool 32 * @build KullaTesting TestingInputStream 33 * @run testng ToolSimpleTest 34 */ 35 import java.util.Arrays; 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.function.Consumer; 39 import java.util.stream.Collectors; 40 import java.util.stream.Stream; 41 42 import org.testng.annotations.Test; 43 44 import static org.testng.Assert.assertEquals; 45 import static org.testng.Assert.assertTrue; 46 47 @Test 48 public class ToolSimpleTest extends ReplToolTesting { 49 50 public void testRemaining() { 51 test( 52 (a) -> assertCommand(a, "int z; z =", "z ==> 0"), 53 (a) -> assertCommand(a, "5", "z ==> 5"), 54 (a) -> assertCommand(a, "/*nada*/; int q =", ""), 55 (a) -> assertCommand(a, "77", "q ==> 77"), 56 (a) -> assertCommand(a, "//comment;", ""), 57 (a) -> assertCommand(a, "int v;", "v ==> 0"), 58 (a) -> assertCommand(a, "int v; int c", 59 "v ==> 0\n" + 60 "c ==> 0") 61 ); 62 } 63 64 public void testOpenComment() { 65 test( 66 (a) -> assertCommand(a, "int z = /* blah", ""), 67 (a) -> assertCommand(a, "baz */ 5", "z ==> 5"), 68 (a) -> assertCommand(a, "/** hoge ", ""), 69 (a) -> assertCommand(a, "baz **/", ""), 70 (a) -> assertCommand(a, "int v", "v ==> 0") 71 ); 72 } 73 74 public void oneLineOfError() { 75 test( 76 (a) -> assertCommand(a, "12+", null), 77 (a) -> assertCommandCheckOutput(a, " true", (s) -> 78 assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'")) 79 ); 80 } 81 82 public void defineVariables() { 83 test( 84 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 85 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 86 (a) -> assertVariable(a, "int", "a"), 87 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 88 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 89 (a) -> assertVariable(a, "double", "a", "1", "1.0"), 90 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 91 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 92 (a) -> evaluateExpression(a, "double", "2 * a", "2.0"), 93 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 94 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()) 95 ); 96 } 97 98 public void defineMethods() { 99 test( 100 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 101 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 102 (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 103 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 104 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 105 (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), 106 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 107 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 108 (a) -> assertMethod(a, "void g() {}", "()void", "g"), 109 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 110 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) 111 ); 112 } 113 114 public void defineTypes() { 115 test( 116 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 117 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 118 (a) -> assertClass(a, "class A { }", "class", "A"), 119 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 120 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 121 (a) -> assertClass(a, "interface A { }", "interface", "A"), 122 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 123 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 124 (a) -> assertClass(a, "enum A { }", "enum", "A"), 125 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 126 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 127 (a) -> assertClass(a, "@interface A { }", "@interface", "A"), 128 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 129 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()) 130 ); 131 } 132 133 public void defineImports() { 134 test( 135 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 136 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 137 (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"), 138 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 139 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 140 (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 141 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 142 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 143 (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"), 144 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 145 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 146 (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"), 147 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 148 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 149 ); 150 } 151 152 public void defineVar() { 153 test( 154 (a) -> assertCommand(a, "int x = 72", "x ==> 72"), 155 (a) -> assertCommand(a, "x", "x ==> 72"), 156 (a) -> assertCommand(a, "/vars", "| int x = 72") 157 ); 158 } 159 160 @Test(enabled = false) // TODO 8153897 161 public void defineUnresolvedVar() { 162 test( 163 (a) -> assertCommand(a, "undefined x", 164 "| created variable x, however, it cannot be referenced until class undefined is declared"), 165 (a) -> assertCommand(a, "/vars", "| undefined x = (not-active)") 166 ); 167 } 168 169 public void testUnresolved() { 170 test( 171 (a) -> assertCommand(a, "int f() { return g() + x + new A().a; }", 172 "| created method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"), 173 (a) -> assertCommand(a, "f()", 174 "| attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"), 175 (a) -> assertCommandOutputStartsWith(a, "int g() { return x; }", 176 "| created method g(), however, it cannot be invoked until variable x is declared"), 177 (a) -> assertCommand(a, "g()", "| attempted to call method g() which cannot be invoked until variable x is declared") 178 ); 179 } 180 181 public void testUnknownCommand() { 182 test((a) -> assertCommand(a, "/unknown", 183 "| No such command or snippet id: /unknown\n" + 184 "| Type /help for help.")); 185 } 186 187 public void testEmptyClassPath() { 188 test(after -> assertCommand(after, "/classpath", "| The /classpath command requires a path argument.")); 189 } 190 191 public void testNoArgument() { 192 test( 193 (a) -> assertCommand(a, "/save", 194 "| '/save' requires a filename argument."), 195 (a) -> assertCommand(a, "/open", 196 "| '/open' requires a filename argument."), 197 (a) -> assertCommand(a, "/set start", 198 "| Specify either one option or a startup file name -- /set start") 199 ); 200 } 201 202 public void testDebug() { 203 test( 204 (a) -> assertCommand(a, "/deb", "| Debugging on"), 205 (a) -> assertCommand(a, "/debug", "| Debugging off"), 206 (a) -> assertCommand(a, "/debug", "| Debugging on"), 207 (a) -> assertCommand(a, "/deb", "| Debugging off") 208 ); 209 } 210 211 public void testDrop() { 212 test(false, new String[]{"--no-startup"}, 213 a -> assertVariable(a, "int", "a"), 214 a -> dropVariable(a, "/drop 1", "int a = 0", "| dropped variable a"), 215 a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), 216 a -> dropMethod(a, "/drop 2", "b ()I", "| dropped method b()"), 217 a -> assertClass(a, "class A {}", "class", "A"), 218 a -> dropClass(a, "/drop 3", "class A", "| dropped class A"), 219 a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 220 a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""), 221 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 222 a -> assertCommandCheckOutput(a, "/methods", assertMethods()), 223 a -> assertCommandCheckOutput(a, "/types", assertClasses()), 224 a -> assertCommandCheckOutput(a, "/imports", assertImports()) 225 ); 226 test(false, new String[]{"--no-startup"}, 227 a -> assertVariable(a, "int", "a"), 228 a -> dropVariable(a, "/drop a", "int a = 0", "| dropped variable a"), 229 a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), 230 a -> dropMethod(a, "/drop b", "b ()I", "| dropped method b()"), 231 a -> assertClass(a, "class A {}", "class", "A"), 232 a -> dropClass(a, "/drop A", "class A", "| dropped class A"), 233 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 234 a -> assertCommandCheckOutput(a, "/methods", assertMethods()), 235 a -> assertCommandCheckOutput(a, "/types", assertClasses()), 236 a -> assertCommandCheckOutput(a, "/imports", assertImports()) 237 ); 238 } 239 240 public void testDropNegative() { 241 test(false, new String[]{"--no-startup"}, 242 a -> assertCommandOutputStartsWith(a, "/drop 0", "| No such snippet: 0"), 243 a -> assertCommandOutputStartsWith(a, "/drop a", "| No such snippet: a"), 244 a -> assertCommandCheckOutput(a, "/drop", 245 assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), 246 a -> assertVariable(a, "int", "a"), 247 a -> assertCommand(a, "a", "a ==> 0"), 248 a -> assertCommand(a, "/drop 2", 249 "| This command does not accept the snippet '2' : a\n" + 250 "| See /types, /methods, /vars, or /list") 251 ); 252 } 253 254 public void testAmbiguousDrop() { 255 Consumer<String> check = s -> { 256 assertTrue(s.startsWith("| The argument references more than one import, variable, method, or class"), s); 257 int lines = s.split("\n").length; 258 assertEquals(lines, 5, "Expected 3 ambiguous keys, but found: " + (lines - 2) + "\n" + s); 259 }; 260 test( 261 a -> assertVariable(a, "int", "a"), 262 a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), 263 a -> assertClass(a, "class a {}", "class", "a"), 264 a -> assertCommandCheckOutput(a, "/drop a", check), 265 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 266 a -> assertCommandCheckOutput(a, "/methods", assertMethods()), 267 a -> assertCommandCheckOutput(a, "/types", assertClasses()), 268 a -> assertCommandCheckOutput(a, "/imports", assertImports()) 269 ); 270 test( 271 a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), 272 a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), 273 a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), 274 a -> assertCommandCheckOutput(a, "/drop a", check), 275 a -> assertCommandCheckOutput(a, "/methods", assertMethods()) 276 ); 277 } 278 279 public void testHelpLength() { 280 Consumer<String> testOutput = (s) -> { 281 List<String> ss = Stream.of(s.split("\n")) 282 .filter(l -> !l.isEmpty()) 283 .collect(Collectors.toList()); 284 assertTrue(ss.size() >= 10, "Help does not print enough lines:" + s); 285 }; 286 test( 287 (a) -> assertCommandCheckOutput(a, "/?", testOutput), 288 (a) -> assertCommandCheckOutput(a, "/help", testOutput), 289 (a) -> assertCommandCheckOutput(a, "/help /list", testOutput) 290 ); 291 } 292 293 public void testHelp() { 294 test( 295 (a) -> assertHelp(a, "/?", "/list", "/help", "/exit", "intro"), 296 (a) -> assertHelp(a, "/help", "/list", "/help", "/exit", "intro"), 297 (a) -> assertHelp(a, "/help short", "shortcuts", "<tab>"), 298 (a) -> assertHelp(a, "/? /li", "/list -all", "snippets"), 299 (a) -> assertHelp(a, "/help /help", "/help <command>") 300 ); 301 } 302 303 private void assertHelp(boolean a, String command, String... find) { 304 assertCommandCheckOutput(a, command, s -> { 305 for (String f : find) { 306 assertTrue(s.contains(f), "Expected output of " + command + " to contain: " + f); 307 } 308 }); 309 } 310 311 // Check that each line of output contains the corresponding string from the list 312 private void checkLineToList(String in, List<String> match) { 313 String trimmed = in.trim(); 314 String[] res = trimmed.isEmpty() 315 ? new String[0] 316 : trimmed.split("\n"); 317 assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res)); 318 for (int i = 0; i < match.size(); ++i) { 319 assertTrue(res[i].contains(match.get(i))); 320 } 321 } 322 323 public void testListArgs() { 324 String arg = "qqqq"; 325 List<String> startVarList = new ArrayList<>(START_UP); 326 startVarList.add("int aardvark"); 327 test( 328 a -> assertCommandCheckOutput(a, "/list -all", 329 s -> checkLineToList(s, START_UP)), 330 a -> assertCommandOutputStartsWith(a, "/list " + arg, 331 "| No such snippet: " + arg), 332 a -> assertVariable(a, "int", "aardvark"), 333 a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"), 334 a -> assertCommandCheckOutput(a, "/list -start", 335 s -> checkLineToList(s, START_UP)), 336 a -> assertCommandCheckOutput(a, "/list -all", 337 s -> checkLineToList(s, startVarList)), 338 a -> assertCommandCheckOutput(a, "/list printf", 339 s -> assertTrue(s.contains("void printf"))), 340 a -> assertCommandOutputStartsWith(a, "/list " + arg, 341 "| No such snippet: " + arg) 342 ); 343 } 344 345 public void testVarsArgs() { 346 String arg = "qqqq"; 347 List<String> startVarList = new ArrayList<>(); 348 test( 349 a -> assertCommandCheckOutput(a, "/vars -all", 350 s -> checkLineToList(s, startVarList)), 351 a -> assertCommand(a, "/vars " + arg, 352 "| No such snippet: " + arg), 353 a -> assertVariable(a, "int", "aardvark"), 354 a -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 355 a -> assertVariable(a, "int", "a"), 356 a -> assertVariable(a, "double", "a", "1", "1.0"), 357 a -> assertCommandOutputStartsWith(a, "/vars aardvark", 358 "| int aardvark = 0"), 359 a -> assertCommandCheckOutput(a, "/vars -start", 360 s -> checkLineToList(s, startVarList)), 361 a -> assertCommandOutputStartsWith(a, "/vars -all", 362 "| int aardvark = 0\n| int a = "), 363 a -> assertCommandOutputStartsWith(a, "/vars printf", 364 "| This command does not accept the snippet 'printf'"), 365 a -> assertCommand(a, "/var " + arg, 366 "| No such snippet: " + arg) 367 ); 368 } 369 370 public void testMethodsArgs() { 371 String arg = "qqqq"; 372 List<String> startMethodList = new ArrayList<>(START_UP_CMD_METHOD); 373 test( 374 a -> assertCommandCheckOutput(a, "/methods -all", 375 s -> checkLineToList(s, startMethodList)), 376 a -> assertCommandCheckOutput(a, "/methods -start", 377 s -> checkLineToList(s, startMethodList)), 378 a -> assertCommandCheckOutput(a, "/methods printf", 379 s -> checkLineToList(s, startMethodList)), 380 a -> assertCommandCheckOutput(a, "/methods", 381 s -> checkLineToList(s, startMethodList)), 382 a -> assertCommandOutputStartsWith(a, "/methods " + arg, 383 "| No such snippet: " + arg), 384 a -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 385 a -> assertVariable(a, "int", "aardvark"), 386 a -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), 387 a -> assertMethod(a, "void g() {}", "()void", "g"), 388 a -> assertCommandOutputStartsWith(a, "/methods " + arg, 389 "| No such snippet: " + arg), 390 a -> assertCommandOutputStartsWith(a, "/methods aardvark", 391 "| This command does not accept the snippet 'aardvark' : int aardvark"), 392 a -> assertCommandCheckOutput(a, "/methods -start", 393 s -> checkLineToList(s, startMethodList)), 394 a -> assertCommandCheckOutput(a, "/methods printf", 395 s -> checkLineToList(s, startMethodList)), 396 a -> assertCommandOutputStartsWith(a, "/methods g", 397 "| g ()void"), 398 a -> assertCommandOutputStartsWith(a, "/methods f", 399 "| f ()int\n" + 400 "| f (int)void") 401 ); 402 } 403 404 public void testTypesArgs() { 405 String arg = "qqqq"; 406 List<String> startTypeList = new ArrayList<>(); 407 test( 408 a -> assertCommandCheckOutput(a, "/types -all", 409 s -> checkLineToList(s, startTypeList)), 410 a -> assertCommandCheckOutput(a, "/types -start", 411 s -> checkLineToList(s, startTypeList)), 412 a -> assertCommandOutputStartsWith(a, "/types " + arg, 413 "| No such snippet: " + arg), 414 a -> assertVariable(a, "int", "aardvark"), 415 (a) -> assertClass(a, "class A { }", "class", "A"), 416 (a) -> assertClass(a, "interface A { }", "interface", "A"), 417 a -> assertCommandOutputStartsWith(a, "/types -all", 418 "| class A\n" + 419 "| interface A"), 420 (a) -> assertClass(a, "enum E { }", "enum", "E"), 421 (a) -> assertClass(a, "@interface B { }", "@interface", "B"), 422 a -> assertCommand(a, "/types aardvark", 423 "| This command does not accept the snippet 'aardvark' : int aardvark;"), 424 a -> assertCommandOutputStartsWith(a, "/types A", 425 "| interface A"), 426 a -> assertCommandOutputStartsWith(a, "/types E", 427 "| enum E"), 428 a -> assertCommandOutputStartsWith(a, "/types B", 429 "| @interface B"), 430 a -> assertCommandOutputStartsWith(a, "/types " + arg, 431 "| No such snippet: " + arg), 432 a -> assertCommandCheckOutput(a, "/types -start", 433 s -> checkLineToList(s, startTypeList)) 434 ); 435 } 436 public void defineClasses() { 437 test( 438 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 439 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 440 (a) -> assertClass(a, "class A { }", "class", "A"), 441 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 442 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 443 (a) -> assertClass(a, "interface A { }", "interface", "A"), 444 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 445 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 446 (a) -> assertClass(a, "enum A { }", "enum", "A"), 447 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 448 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 449 (a) -> assertClass(a, "@interface A { }", "@interface", "A"), 450 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 451 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()) 452 ); 453 } 454 public void testCommandPrefix() { 455 test(a -> assertCommandCheckOutput(a, "/s", 456 assertStartsWith("| Command: '/s' is ambiguous: /save, /set")), 457 a -> assertCommand(a, "int var", "var ==> 0"), 458 a -> assertCommandCheckOutput(a, "/va", 459 assertStartsWith("| int var = 0")), 460 a -> assertCommandCheckOutput(a, "/save", 461 assertStartsWith("| '/save' requires a filename argument."))); 462 } 463 464 public void testOptionQ() { 465 test(new String[]{"-q", "--no-startup"}, 466 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 467 (a) -> assertCommand(a, "int x = 5", "") 468 ); 469 } 470 471 public void testOptionQq() { 472 test(new String[]{"-s", "--no-startup"}, 473 (a) -> assertCommand(a, "1+1", "") 474 ); 475 } 476 477 public void testOptionV() { 478 test(new String[]{"-v", "--no-startup"}, 479 (a) -> assertCommand(a, "1+1", 480 "$1 ==> 2\n" + 481 "| created scratch variable $1 : int") 482 ); 483 } 484 485 public void testOptionFeedback() { 486 test(new String[]{"--feedback", "concise", "--no-startup"}, 487 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 488 (a) -> assertCommand(a, "int x = 5", "") 489 ); 490 } 491 492 public void testOptionR() { 493 test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"}, 494 (a) -> assertCommand(a, "System.getProperty(\"the.sound\")", 495 "$1 ==> \"blorp\"") 496 ); 497 } 498 499 public void test8156910() { 500 test( 501 (a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"), 502 (a) -> assertCommandOutputContains(a, "1234", "==> 1234") 503 ); 504 } 505 }