1 /* 2 * Copyright (c) 2016, 2018, 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 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801 8210596 8210959 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/othervm ToolSimpleTest 34 */ 35 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.List; 39 import java.util.Locale; 40 import java.util.function.Consumer; 41 import java.util.regex.Pattern; 42 import java.util.stream.Collectors; 43 import java.util.stream.Stream; 44 45 import org.testng.annotations.Test; 46 47 import static org.testng.Assert.assertEquals; 48 import static org.testng.Assert.assertTrue; 49 50 public class ToolSimpleTest extends ReplToolTesting { 51 52 @Test 53 public void testRemaining() { 54 test( 55 (a) -> assertCommand(a, "int z; z =", "z ==> 0"), 56 (a) -> assertCommand(a, "5", "z ==> 5"), 57 (a) -> assertCommand(a, "/*nada*/; int q =", ""), 58 (a) -> assertCommand(a, "77", "q ==> 77"), 59 (a) -> assertCommand(a, "//comment;", ""), 60 (a) -> assertCommand(a, "int v;", "v ==> 0"), 61 (a) -> assertCommand(a, "int v; int c", 62 "v ==> 0\n" + 63 "c ==> 0") 64 ); 65 } 66 67 @Test 68 public void testOpenComment() { 69 test( 70 (a) -> assertCommand(a, "int z = /* blah", ""), 71 (a) -> assertCommand(a, "baz */ 5", "z ==> 5"), 72 (a) -> assertCommand(a, "/** hoge ", ""), 73 (a) -> assertCommand(a, "baz **/", ""), 74 (a) -> assertCommand(a, "int v", "v ==> 0") 75 ); 76 } 77 78 @Test 79 public void testRawString() { 80 test(false, new String[]{"--enable-preview", "--no-startup"}, 81 (a) -> assertCommand(a, "String s = `abc`", "s ==> \"abc\""), 82 (a) -> assertCommand(a, "String a = `abc", ""), 83 (a) -> assertCommand(a, "def`", "a ==> \"abc\\ndef\""), 84 (a) -> assertCommand(a, "String bj = ``Hi, `Bob` and ```Jim```.``", "bj ==> \"Hi, `Bob` and ```Jim```.\""), 85 (a) -> assertCommand(a, "String hw = ````````````", ""), 86 (a) -> assertCommand(a, "Hello, world", ""), 87 (a) -> assertCommand(a, "````````````;", "hw ==> \"\\nHello, world\\n\""), 88 (a) -> assertCommand(a, "String uc = `\\u000d\\u000a`", "uc ==> \"\\\\u000d\\\\u000a\""), 89 (a) -> assertCommand(a, "String es = `\\(.\\)\\1`", "es ==> \"\\\\(.\\\\)\\\\1\""), 90 (a) -> assertCommand(a, "String end = `abc`+`def`+`ghi`", "end ==> \"abcdefghi\"") 91 ); 92 } 93 94 @Test 95 public void testSwitchExpression() { 96 test(false, new String[]{"--enable-preview", "--no-startup"}, 97 (a) -> assertCommand(a, "enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }", "| created enum Day"), 98 (a) -> assertCommand(a, "Day day = Day.FRIDAY;", "day ==> FRIDAY"), 99 (a) -> assertCommand(a, "switch (day) {", ""), 100 (a) -> assertCommand(a, "case MONDAY, FRIDAY, SUNDAY -> 6;", ""), 101 (a) -> assertCommand(a, "case TUESDAY -> 7;", ""), 102 (a) -> assertCommand(a, "case THURSDAY, SATURDAY -> 8;", ""), 103 (a) -> assertCommand(a, "case WEDNESDAY -> 9;", ""), 104 (a) -> assertCommandOutputContains(a, "}", " ==> 6") 105 ); 106 } 107 108 @Test 109 public void testSwitchExpressionCompletion() { 110 test(false, new String[]{"--enable-preview", "--no-startup"}, 111 (a) -> assertCommand(a, "enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }", "| created enum Day"), 112 (a) -> assertCommand(a, "Day day = Day.FRIDAY;", "day ==> FRIDAY"), 113 (a) -> assertCommand(a, "switch (day) {", ""), 114 (a) -> assertCommand(a, "case MONDAY, FRIDAY, SUNDAY -> 6;", ""), 115 (a) -> assertCommand(a, "case TUESDAY -> 7;", ""), 116 (a) -> assertCommand(a, "case THURSDAY, SATURDAY -> 8;", ""), 117 (a) -> assertCommand(a, "case WEDNESDAY -> 9;", ""), 118 (a) -> assertCommand(a, "} +", ""), 119 (a) -> assertCommandOutputContains(a, "1000", " ==> 1006") 120 ); 121 } 122 123 @Test 124 public void testLessThan() { 125 test( 126 (a) -> assertCommand(a, "45", "$1 ==> 45"), 127 (a) -> assertCommand(a, "72", "$2 ==> 72"), 128 (a) -> assertCommand(a, "$1 < $2", "$3 ==> true"), 129 (a) -> assertCommand(a, "int a, b", "a ==> 0\n" + 130 "b ==> 0"), 131 (a) -> assertCommand(a, "a < b", "$6 ==> false") 132 ); 133 } 134 135 @Test 136 public void testChainedThrow() { 137 test( 138 (a) -> assertCommand(a, "void p() throws Exception { ((String) null).toString(); }", 139 "| created method p()"), 140 (a) -> assertCommand(a, "void n() throws Exception { try { p(); } catch (Exception ex) { throw new IOException(\"bar\", ex); }}", 141 "| created method n()"), 142 (a) -> assertCommand(a, "void m() { try { n(); } catch (Exception ex) { throw new RuntimeException(\"foo\", ex); }}", 143 "| created method m()"), 144 (a) -> assertCommand(a, "m()", 145 "| Exception java.lang.RuntimeException: foo\n" 146 + "| at m (#3:1)\n" 147 + "| at (#4:1)\n" 148 + "| Caused by: java.io.IOException: bar\n" 149 + "| at n (#2:1)\n" 150 + "| ...\n" 151 + "| Caused by: java.lang.NullPointerException\n" 152 + "| at p (#1:1)\n" 153 + "| ..."), 154 (a) -> assertCommand(a, "/drop p", 155 "| dropped method p()"), 156 (a) -> assertCommand(a, "m()", 157 "| attempted to call method n() which cannot be invoked until method p() is declared") 158 ); 159 } 160 161 @Test 162 public void testThrowWithPercent() { 163 test( 164 (a) -> assertCommandCheckOutput(a, 165 "URI u = new URI(\"http\", null, \"h\", -1, \"a\" + (char)0x04, null, null);", (s) -> 166 assertTrue(s.contains("URISyntaxException") && !s.contains("JShellTool"), 167 "Output: '" + s + "'")), 168 (a) -> assertCommandCheckOutput(a, 169 "throw new Exception(\"%z\")", (s) -> 170 assertTrue(s.contains("java.lang.Exception") && !s.contains("UnknownFormatConversionException"), 171 "Output: '" + s + "'")) 172 ); 173 } 174 175 @Test 176 public void oneLineOfError() { 177 test( 178 (a) -> assertCommand(a, "12+", null), 179 (a) -> assertCommandCheckOutput(a, " true", (s) -> 180 assertTrue(s.contains("12+") && !s.contains("true"), "Output: '" + s + "'")) 181 ); 182 } 183 184 @Test 185 public void defineVariables() { 186 test( 187 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 188 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 189 (a) -> assertVariable(a, "int", "a"), 190 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 191 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 192 (a) -> assertVariable(a, "double", "a", "1", "1.0"), 193 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 194 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 195 (a) -> evaluateExpression(a, "double", "2 * a", "2.0"), 196 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 197 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()) 198 ); 199 } 200 201 @Test 202 public void defineMethods() { 203 test( 204 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 205 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 206 (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 207 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 208 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 209 (a) -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), 210 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 211 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 212 (a) -> assertMethod(a, "void g() {}", "()void", "g"), 213 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 214 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) 215 ); 216 } 217 218 @Test 219 public void defineTypes() { 220 test( 221 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 222 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 223 (a) -> assertClass(a, "class A { }", "class", "A"), 224 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 225 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 226 (a) -> assertClass(a, "interface A { }", "interface", "A"), 227 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 228 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 229 (a) -> assertClass(a, "enum A { }", "enum", "A"), 230 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 231 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 232 (a) -> assertClass(a, "@interface A { }", "@interface", "A"), 233 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 234 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()) 235 ); 236 } 237 238 @Test 239 public void defineImports() { 240 test( 241 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 242 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 243 (a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"), 244 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 245 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 246 (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 247 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 248 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 249 (a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"), 250 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 251 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 252 (a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"), 253 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 254 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 255 ); 256 } 257 258 @Test 259 public void defineVar() { 260 test( 261 (a) -> assertCommand(a, "int x = 72", "x ==> 72"), 262 (a) -> assertCommand(a, "x", "x ==> 72"), 263 (a) -> assertCommand(a, "/vars", "| int x = 72") 264 ); 265 } 266 267 @Test 268 public void defineUnresolvedVar() { 269 test( 270 (a) -> assertCommand(a, "undefined x", 271 "| created variable x, however, it cannot be referenced until class undefined is declared"), 272 (a) -> assertCommand(a, "/vars", "| undefined x = (not-active)") 273 ); 274 } 275 276 @Test 277 public void testUnresolved() { 278 test( 279 (a) -> assertCommand(a, "int f() { return g() + x + new A().a; }", 280 "| created method f(), however, it cannot be invoked until method g(), variable x, and class A are declared"), 281 (a) -> assertCommand(a, "f()", 282 "| attempted to call method f() which cannot be invoked until method g(), variable x, and class A are declared"), 283 (a) -> assertCommandOutputStartsWith(a, "int g() { return x; }", 284 "| created method g(), however, it cannot be invoked until variable x is declared"), 285 (a) -> assertCommand(a, "g()", "| attempted to call method g() which cannot be invoked until variable x is declared") 286 ); 287 } 288 289 @Test 290 public void testUnknownCommand() { 291 test((a) -> assertCommand(a, "/unknown", 292 "| Invalid command: /unknown\n" + 293 "| Type /help for help.")); 294 } 295 296 @Test 297 public void testEmptyClassPath() { 298 test(after -> assertCommand(after, "/env --class-path", "| Argument to class-path missing.")); 299 } 300 301 @Test 302 public void testInvalidClassPath() { 303 test( 304 a -> assertCommand(a, "/env --class-path snurgefusal", 305 "| File 'snurgefusal' for '--class-path' is not found."), 306 a -> assertCommand(a, "/env --class-path ?", 307 "| File '?' for '--class-path' is not found.") 308 ); 309 } 310 311 @Test 312 public void testNoArgument() { 313 test( 314 (a) -> assertCommand(a, "/save", 315 "| '/save' requires a filename argument."), 316 (a) -> assertCommand(a, "/open", 317 "| '/open' requires a filename argument."), 318 (a) -> assertCommandOutputStartsWith(a, "/drop", 319 "| In the /drop argument, please specify an import, variable, method, or class to drop.") 320 ); 321 } 322 323 @Test 324 public void testDebug() { 325 test( 326 (a) -> assertCommand(a, "/deb", "| Debugging on"), 327 (a) -> assertCommand(a, "/debug", "| Debugging off"), 328 (a) -> assertCommand(a, "/debug", "| Debugging on"), 329 (a) -> assertCommand(a, "/deb", "| Debugging off") 330 ); 331 } 332 333 @Test 334 public void testDrop() { 335 test(false, new String[]{"--no-startup"}, 336 a -> assertVariable(a, "int", "a"), 337 a -> dropVariable(a, "/drop 1", "int a = 0", "| dropped variable a"), 338 a -> assertMethod(a, "int b() { return 0; }", "()int", "b"), 339 a -> dropMethod(a, "/drop 2", "int b()", "| dropped method b()"), 340 a -> assertClass(a, "class A {}", "class", "A"), 341 a -> dropClass(a, "/drop 3", "class A", "| dropped class A"), 342 a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 343 a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""), 344 a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""), 345 a -> assertCommand(a, "/drop 5", ""), 346 a -> assertCommand(a, "/list", ""), 347 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 348 a -> assertCommandCheckOutput(a, "/methods", assertMethods()), 349 a -> assertCommandCheckOutput(a, "/types", assertClasses()), 350 a -> assertCommandCheckOutput(a, "/imports", assertImports()) 351 ); 352 test(false, new String[]{"--no-startup"}, 353 a -> assertVariable(a, "int", "a"), 354 a -> dropVariable(a, "/drop a", "int a = 0", "| dropped variable a"), 355 a -> assertMethod(a, "int b() { return 0; }", "()int", "b"), 356 a -> dropMethod(a, "/drop b", "int b()", "| dropped method b()"), 357 a -> assertClass(a, "class A {}", "class", "A"), 358 a -> dropClass(a, "/drop A", "class A", "| dropped class A"), 359 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 360 a -> assertCommandCheckOutput(a, "/methods", assertMethods()), 361 a -> assertCommandCheckOutput(a, "/types", assertClasses()), 362 a -> assertCommandCheckOutput(a, "/imports", assertImports()) 363 ); 364 } 365 366 @Test 367 public void testDropRange() { 368 test(false, new String[]{"--no-startup"}, 369 a -> assertVariable(a, "int", "a"), 370 a -> assertMethod(a, "int b() { return 0; }", "()int", "b"), 371 a -> assertClass(a, "class A {}", "class", "A"), 372 a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 373 a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""), 374 a -> assertCommand(a, "/drop 3-5 b 1", 375 "| dropped class A\n" + 376 "| dropped method b()\n" + 377 "| dropped variable a\n"), 378 a -> assertCommand(a, "/list", "") 379 ); 380 } 381 382 @Test 383 public void testDropNegative() { 384 test(false, new String[]{"--no-startup"}, 385 a -> assertCommandOutputStartsWith(a, "/drop 0", "| No snippet with ID: 0"), 386 a -> assertCommandOutputStartsWith(a, "/drop a", "| No such snippet: a"), 387 a -> assertCommandCheckOutput(a, "/drop", 388 assertStartsWith("| In the /drop argument, please specify an import, variable, method, or class to drop.")), 389 a -> assertVariable(a, "int", "a"), 390 a -> assertCommand(a, "a", "a ==> 0"), 391 a -> assertCommand(a, "/drop 2", ""), 392 a -> assertCommand(a, "/drop 2", 393 "| This command does not accept the snippet '2' : a\n" + 394 "| See /types, /methods, /vars, or /list") 395 ); 396 } 397 398 @Test 399 public void testAmbiguousDrop() { 400 test( 401 a -> assertVariable(a, "int", "a"), 402 a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), 403 a -> assertClass(a, "class a {}", "class", "a"), 404 a -> assertCommand(a, "/drop a", 405 "| dropped variable a\n" + 406 "| dropped method a()\n" + 407 "| dropped class a") 408 ); 409 test( 410 a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), 411 a -> assertMethod(a, "double a(int a) { return 0; }", "(int)double", "a"), 412 a -> assertMethod(a, "double a(double a) { return 0; }", "(double)double", "a"), 413 a -> assertCommand(a, "/drop a", 414 "| dropped method a()\n" + 415 "| dropped method a(int)\n" + 416 "| dropped method a(double)\n") 417 ); 418 } 419 420 @Test 421 public void testApplicationOfPost() { 422 test( 423 (a) -> assertCommand(a, "/set mode t normal -command", "| Created new feedback mode: t"), 424 (a) -> assertCommand(a, "/set feedback t", "| Feedback mode: t"), 425 (a) -> assertCommand(a, "/set format t post \"$%n\"", ""), 426 (a) -> assertCommand(a, "/set prompt t \"+\" \"-\"", ""), 427 (a) -> assertCommand(a, "/set prompt t", "| /set prompt t \"+\" \"-\"$") 428 ); 429 } 430 431 @Test 432 public void testHelpLength() { 433 Consumer<String> testOutput = (s) -> { 434 List<String> ss = Stream.of(s.split("\n")) 435 .filter(l -> !l.isEmpty()) 436 .collect(Collectors.toList()); 437 assertTrue(ss.size() >= 10, "Help does not print enough lines:" + s); 438 }; 439 test( 440 (a) -> assertCommandCheckOutput(a, "/?", testOutput), 441 (a) -> assertCommandCheckOutput(a, "/help", testOutput), 442 (a) -> assertCommandCheckOutput(a, "/help /list", testOutput) 443 ); 444 } 445 446 @Test 447 public void testHelp() { 448 test( 449 (a) -> assertHelp(a, "/?", "/list", "/help", "/exit", "intro"), 450 (a) -> assertHelp(a, "/help", "/list", "/help", "/exit", "intro"), 451 (a) -> assertHelp(a, "/help short", "shortcuts", "<tab>"), 452 (a) -> assertHelp(a, "/? /li", "/list -all", "snippets"), 453 (a) -> assertHelp(a, "/help /set prompt", "optionally contain '%s'", "quoted"), 454 (a) -> assertHelp(a, "/help /help", "/help <command>"), 455 (a) -> assertHelp(a, "/help li", "/list -start"), 456 (a) -> assertHelp(a, "/help fe", "/set feedback -retain") 457 ); 458 } 459 460 @Test 461 public void testHelpStart() { 462 test( 463 (a) -> assertCommandCheckOutput(a, "/help /exit", 464 s -> assertTrue(s.replaceAll("\\r\\n?", "\n").startsWith( 465 "| \n" + 466 "| /exit\n" + 467 "| =====\n" + 468 "| " 469 )) 470 ) 471 ); 472 } 473 474 @Test 475 public void testHelpFormat() { 476 test( 477 (a) -> assertCommandCheckOutput(a, "/help", s -> { 478 String[] lines = s.split("\\R"); 479 assertTrue(lines.length > 20, 480 "Too few lines of /help output: " + lines.length 481 + "\n" + s); 482 for (int i = 0; i < lines.length; ++i) { 483 String l = lines[i]; 484 assertTrue(l.startsWith("| "), 485 "Expected /help line to start with | :\n" + l); 486 assertTrue(l.length() <= 80, 487 "/help line too long: " + l.length() + "\n" + l); 488 } 489 }) 490 ); 491 } 492 493 @Test 494 public void testConfusedUserPseudoCommands() { 495 test( 496 (a) -> assertHelp(a, "/-<n>", "last snippet", "digits"), 497 (a) -> assertHelp(a, "/<id>", "last snippet", "digits") 498 ); 499 } 500 501 private void assertHelp(boolean a, String command, String... find) { 502 assertCommandCheckOutput(a, command, s -> { 503 for (String f : find) { 504 assertTrue(s.contains(f), 505 "Expected output of " + command + " to contain: " + f 506 + "\n" + s); 507 } 508 }); 509 } 510 511 // Check that each line of output contains the corresponding string from the list 512 private void checkLineToList(String in, List<String> match) { 513 String trimmed = in.trim(); 514 String[] res = trimmed.isEmpty() 515 ? new String[0] 516 : trimmed.split("\n"); 517 assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res)); 518 for (int i = 0; i < match.size(); ++i) { 519 assertTrue(res[i].contains(match.get(i))); 520 } 521 } 522 523 @Test 524 public void testListArgs() { 525 String arg = "qqqq"; 526 List<String> startVarList = new ArrayList<>(START_UP); 527 startVarList.add("int aardvark"); 528 startVarList.add("int weevil"); 529 test( 530 a -> assertCommandCheckOutput(a, "/list -all", 531 s -> checkLineToList(s, START_UP)), 532 a -> assertCommandOutputStartsWith(a, "/list " + arg, 533 "| No such snippet: " + arg), 534 a -> assertVariable(a, "int", "aardvark"), 535 a -> assertVariable(a, "int", "weevil"), 536 a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"), 537 a -> assertCommandCheckOutput(a, "/list -start", 538 s -> checkLineToList(s, START_UP)), 539 a -> assertCommandCheckOutput(a, "/list -all", 540 s -> checkLineToList(s, startVarList)), 541 a -> assertCommandOutputStartsWith(a, "/list s3", 542 "s3 : import"), 543 a -> assertCommandCheckOutput(a, "/list 1-2 s3", 544 s -> { 545 assertTrue(Pattern.matches(".*aardvark.*\\R.*weevil.*\\R.*s3.*import.*", s.trim()), 546 "No match: " + s); 547 }), 548 a -> assertCommandOutputStartsWith(a, "/list " + arg, 549 "| No such snippet: " + arg) 550 ); 551 } 552 553 @Test 554 public void testVarsArgs() { 555 String arg = "qqqq"; 556 List<String> startVarList = new ArrayList<>(); 557 test( 558 a -> assertCommandCheckOutput(a, "/vars -all", 559 s -> checkLineToList(s, startVarList)), 560 a -> assertCommand(a, "/vars " + arg, 561 "| No such snippet: " + arg), 562 a -> assertVariable(a, "int", "aardvark"), 563 a -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 564 a -> assertVariable(a, "int", "a"), 565 a -> assertVariable(a, "double", "a", "1", "1.0"), 566 a -> assertCommandOutputStartsWith(a, "/vars aardvark", 567 "| int aardvark = 0"), 568 a -> assertCommandCheckOutput(a, "/vars -start", 569 s -> checkLineToList(s, startVarList)), 570 a -> assertCommandOutputStartsWith(a, "/vars -all", 571 "| int aardvark = 0\n| int a = "), 572 a -> assertCommandOutputStartsWith(a, "/vars 1-4", 573 "| int aardvark = 0\n| int a = "), 574 a -> assertCommandOutputStartsWith(a, "/vars f", 575 "| This command does not accept the snippet 'f'"), 576 a -> assertCommand(a, "/var " + arg, 577 "| No such snippet: " + arg) 578 ); 579 } 580 581 @Test 582 public void testMethodsArgs() { 583 String arg = "qqqq"; 584 List<String> printingMethodList = new ArrayList<>(PRINTING_CMD_METHOD); 585 test(new String[]{"--startup", "PRINTING"}, 586 a -> assertCommandCheckOutput(a, "/methods -all", 587 s -> checkLineToList(s, printingMethodList)), 588 a -> assertCommandCheckOutput(a, "/methods -start", 589 s -> checkLineToList(s, printingMethodList)), 590 a -> assertCommandCheckOutput(a, "/methods print println printf", 591 s -> checkLineToList(s, printingMethodList)), 592 a -> assertCommandCheckOutput(a, "/methods println", 593 s -> assertEquals(s.trim().split("\n").length, 10)), 594 a -> assertCommandCheckOutput(a, "/methods", 595 s -> checkLineToList(s, printingMethodList)), 596 a -> assertCommandOutputStartsWith(a, "/methods " + arg, 597 "| No such snippet: " + arg), 598 a -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 599 a -> assertVariable(a, "int", "aardvark"), 600 a -> assertMethod(a, "void f(int a) { g(); }", "(int)void", "f"), 601 a -> assertMethod(a, "void g() {}", "()void", "g"), 602 a -> assertCommandOutputStartsWith(a, "/methods " + arg, 603 "| No such snippet: " + arg), 604 a -> assertCommandOutputStartsWith(a, "/methods aardvark", 605 "| This command does not accept the snippet 'aardvark' : int aardvark"), 606 a -> assertCommandCheckOutput(a, "/methods -start", 607 s -> checkLineToList(s, printingMethodList)), 608 a -> assertCommandCheckOutput(a, "/methods print println printf", 609 s -> checkLineToList(s, printingMethodList)), 610 a -> assertCommandOutputStartsWith(a, "/methods g", 611 "| void g()"), 612 a -> assertCommandOutputStartsWith(a, "/methods f", 613 "| int f()\n" + 614 "| void f(int)") 615 ); 616 } 617 618 @Test 619 public void testMethodsWithErrors() { 620 test(new String[]{"--no-startup"}, 621 a -> assertCommand(a, "double m(int x) { return x; }", 622 "| created method m(int)"), 623 a -> assertCommand(a, "GARBAGE junk() { return TRASH; }", 624 "| created method junk(), however, it cannot be referenced until class GARBAGE, and variable TRASH are declared"), 625 a -> assertCommand(a, "int w = 5;", 626 "w ==> 5"), 627 a -> assertCommand(a, "int tyer() { return w; }", 628 "| created method tyer()"), 629 a -> assertCommand(a, "String w = \"hi\";", 630 "w ==> \"hi\""), 631 a -> assertCommand(a, "/methods", 632 "| double m(int)\n" + 633 "| GARBAGE junk()\n" + 634 "| which cannot be referenced until class GARBAGE, and variable TRASH are declared\n" + 635 "| int tyer()\n" + 636 "| which cannot be invoked until this error is corrected: \n" + 637 "| incompatible types: java.lang.String cannot be converted to int\n" + 638 "| int tyer() { return w; }\n" + 639 "| ^\n") 640 ); 641 } 642 643 @Test 644 public void testTypesWithErrors() { 645 test(new String[]{"--no-startup"}, 646 a -> assertCommand(a, "class C extends NONE { int x; }", 647 "| created class C, however, it cannot be referenced until class NONE is declared"), 648 a -> assertCommand(a, "class D { void m() { System.out.println(nada); } }", 649 "| created class D, however, it cannot be instantiated or its methods invoked until variable nada is declared"), 650 a -> assertCommand(a, "/types", 651 "| class C\n" + 652 "| which cannot be referenced until class NONE is declared\n" + 653 "| class D\n" + 654 "| which cannot be instantiated or its methods invoked until variable nada is declared\n") 655 ); 656 } 657 658 @Test 659 public void testTypesArgs() { 660 String arg = "qqqq"; 661 List<String> startTypeList = new ArrayList<>(); 662 test( 663 a -> assertCommandCheckOutput(a, "/types -all", 664 s -> checkLineToList(s, startTypeList)), 665 a -> assertCommandCheckOutput(a, "/types -start", 666 s -> checkLineToList(s, startTypeList)), 667 a -> assertCommandOutputStartsWith(a, "/types " + arg, 668 "| No such snippet: " + arg), 669 a -> assertVariable(a, "int", "aardvark"), 670 (a) -> assertClass(a, "class A { }", "class", "A"), 671 (a) -> assertClass(a, "interface A { }", "interface", "A"), 672 a -> assertCommandOutputStartsWith(a, "/types -all", 673 "| class A\n" + 674 "| interface A"), 675 (a) -> assertClass(a, "enum E { }", "enum", "E"), 676 (a) -> assertClass(a, "@interface B { }", "@interface", "B"), 677 a -> assertCommand(a, "/types aardvark", 678 "| This command does not accept the snippet 'aardvark' : int aardvark;"), 679 a -> assertCommandOutputStartsWith(a, "/types A", 680 "| interface A"), 681 a -> assertCommandOutputStartsWith(a, "/types E", 682 "| enum E"), 683 a -> assertCommandOutputStartsWith(a, "/types B", 684 "| @interface B"), 685 a -> assertCommandOutputStartsWith(a, "/types " + arg, 686 "| No such snippet: " + arg), 687 a -> assertCommandCheckOutput(a, "/types -start", 688 s -> checkLineToList(s, startTypeList)) 689 ); 690 } 691 692 @Test 693 public void testBlankLinesInSnippetContinuation() { 694 test(Locale.ROOT, false, new String[]{"--no-startup"}, "", 695 a -> assertCommand(a, "class C {", 696 ""), 697 a -> assertCommand(a, "", 698 ""), 699 a -> assertCommand(a, "", 700 ""), 701 a -> assertCommand(a, " int x;", 702 ""), 703 a -> assertCommand(a, "", 704 ""), 705 a -> assertCommand(a, "", 706 ""), 707 a -> assertCommand(a, "}", 708 "| created class C"), 709 a -> assertCommand(a, "/list", 710 "\n" + 711 " 1 : class C {\n" + 712 " \n" + 713 " \n" + 714 " int x;\n" + 715 " \n" + 716 " \n" + 717 " }") 718 ); 719 } 720 721 @Test 722 public void testCompoundStart() { 723 test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING"}, 724 (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)", 725 "", "", null, "3.14", "") 726 ); 727 } 728 729 @Test 730 public void testJavaSeStart() { 731 test(new String[]{"--startup", "JAVASE"}, 732 (a) -> assertCommand(a, "ZoneOffsetTransitionRule.TimeDefinition.WALL", 733 "$1 ==> WALL") 734 ); 735 } 736 737 @Test 738 public void testJavaSeSetStart() { 739 test( 740 (a) -> assertCommand(a, "/set sta JAVASE", ""), 741 (a) -> assertCommand(a, "/reset", "| Resetting state."), 742 (a) -> assertCommandCheckOutput(a, "/li -a", 743 s -> assertTrue(s.split("import ").length > 160, 744 "not enough imports for JAVASE:\n" + s)) 745 ); 746 } 747 748 @Test 749 public void defineClasses() { 750 test( 751 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 752 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 753 (a) -> assertClass(a, "class A { }", "class", "A"), 754 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 755 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 756 (a) -> assertClass(a, "interface A { }", "interface", "A"), 757 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 758 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 759 (a) -> assertClass(a, "enum A { }", "enum", "A"), 760 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 761 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 762 (a) -> assertClass(a, "@interface A { }", "@interface", "A"), 763 (a) -> assertCommandCheckOutput(a, "/list", assertList()), 764 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()) 765 ); 766 } 767 768 @Test 769 public void testCommandPrefix() { 770 test(a -> assertCommandCheckOutput(a, "/s", 771 assertStartsWith("| Command: '/s' is ambiguous: /save, /set")), 772 a -> assertCommand(a, "int var", "var ==> 0"), 773 a -> assertCommandCheckOutput(a, "/va", 774 assertStartsWith("| int var = 0")), 775 a -> assertCommandCheckOutput(a, "/save", 776 assertStartsWith("| '/save' requires a filename argument."))); 777 } 778 779 @Test 780 public void testOptionQ() { 781 test(Locale.ROOT, false, new String[]{"-q", "--no-startup"}, "", 782 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 783 (a) -> assertCommand(a, "int x = 5", "") 784 ); 785 } 786 787 @Test 788 public void testOptionS() { 789 test(Locale.ROOT, false, new String[]{"-s", "--no-startup"}, "", 790 (a) -> assertCommand(a, "1+1", "") 791 ); 792 } 793 794 @Test 795 public void testOptionV() { 796 test(new String[]{"-v", "--no-startup"}, 797 (a) -> assertCommand(a, "1+1", 798 "$1 ==> 2\n" + 799 "| created scratch variable $1 : int") 800 ); 801 } 802 803 @Test 804 public void testOptionFeedback() { 805 test(Locale.ROOT, false, new String[]{"--feedback", "concise", "--no-startup"}, "", 806 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 807 (a) -> assertCommand(a, "int x = 5", "") 808 ); 809 } 810 811 @Test 812 public void testCompoundOptions() { 813 Consumer<String> confirmNoStartup = s -> { 814 assertEquals(0, Stream.of(s.split("\n")) 815 .filter(l -> !l.isEmpty()) 816 .count(), "Expected no lines: " + s); 817 }; 818 test(Locale.ROOT, false, new String[]{"-nq"}, "", 819 (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), 820 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 821 (a) -> assertCommand(a, "int x = 5", "") 822 ); 823 test(Locale.ROOT, false, new String[]{"-qn"}, "", 824 (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), 825 (a) -> assertCommand(a, "1+1", "$1 ==> 2"), 826 (a) -> assertCommand(a, "int x = 5", "") 827 ); 828 test(Locale.ROOT, false, new String[]{"-ns"}, "", 829 (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), 830 (a) -> assertCommand(a, "1+1", "") 831 ); 832 } 833 834 @Test 835 public void testOptionR() { 836 test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"}, 837 (a) -> assertCommand(a, "System.getProperty(\"the.sound\")", 838 "$1 ==> \"blorp\"") 839 ); 840 } 841 842 @Test 843 public void testWrapSourceHandlerDiagCrash() { 844 test(new String[]{"--add-exports", "jdk.javadoc/ALL-UNNAMED"}, 845 (a) -> assertCommand(a, "1+1", "$1 ==> 2") 846 ); 847 } 848 849 @Test 850 public void test8156910() { 851 test( 852 (a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"), 853 (a) -> assertCommandOutputContains(a, "1234", "==> 1234") 854 ); 855 } 856 857 @Test 858 public void testIntersection() { 859 test( 860 (a) -> assertCommandOutputContains(a, "<Z extends Runnable&CharSequence> Z get1() { return null; }", "get1()"), 861 (a) -> assertCommandOutputContains(a, "var g1 = get1()", "g1"), 862 (a) -> assertCommand(a, "/vars g1", "| CharSequence&Runnable g1 = null"), 863 (a) -> assertCommandOutputContains(a, "<Z extends Number&CharSequence> Z get2() { return null; }", "get2()"), 864 (a) -> assertCommandOutputContains(a, "var g2 = get2()", "g2"), 865 (a) -> assertCommand(a, "/vars g2", "| Number&CharSequence g2 = null") 866 ); 867 } 868 869 @Test 870 public void testAnonymous() { 871 test( 872 (a) -> assertCommandOutputContains(a, "var r1 = new Object() {}", "r1"), 873 (a) -> assertCommandOutputContains(a, "/vars r1", "| <anonymous class extending Object> r1 = "), 874 (a) -> assertCommandOutputContains(a, "var r2 = new Runnable() { public void run() { } }", "r2"), 875 (a) -> assertCommandOutputContains(a, "/vars r2", "| <anonymous class implementing Runnable> r2 = "), 876 (a) -> assertCommandOutputContains(a, "import java.util.stream.*;", ""), 877 (a) -> assertCommandOutputContains(a, "var list = Stream.of(1, 2, 3).map(j -> new Object() { int i = j; }).collect(Collectors.toList());", 878 "list"), 879 (a) -> assertCommandOutputContains(a, "/vars list", "| List<<anonymous class extending Object>> list = ") 880 ); 881 } 882 883 // This is mainly interesting in the TestLocalSimpleTest case (8198573) 884 @Test 885 public void testUpdateFalsePositive() { 886 test( 887 a -> assertClass(a, "class A { int a() { int error = 0; return error; } }", "class", "A"), 888 a -> assertVariable(a, "A", "a", "new A()", "A@.+"), 889 a -> assertVariable(a, "int", "error", "4711", "4711"), 890 a -> assertCommandOutputContains(a, "a", "A@") 891 ); 892 } 893 }