1 /* 2 * Copyright (c) 2015, 2017, 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 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 8170162 8172102 8165405 8174796 8174797 8175304 8167554 8180508 8166232 8196133 27 * @summary Tests for Basic tests for REPL tool 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 * @library /tools/lib 33 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask 34 * @build KullaTesting TestingInputStream Compiler 35 * @run testng/timeout=600 ToolBasicTest 36 */ 37 38 import java.io.File; 39 import java.io.IOException; 40 import java.io.PrintWriter; 41 import java.io.StringWriter; 42 import java.nio.file.Files; 43 import java.nio.file.Path; 44 import java.nio.file.Paths; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.List; 48 import java.util.Scanner; 49 import java.util.function.BiFunction; 50 import java.util.function.Consumer; 51 import java.util.function.Function; 52 import java.util.stream.Collectors; 53 import java.util.stream.Stream; 54 55 import org.testng.annotations.Test; 56 57 import static org.testng.Assert.assertEquals; 58 import static org.testng.Assert.assertTrue; 59 import static org.testng.Assert.fail; 60 61 @Test 62 public class ToolBasicTest extends ReplToolTesting { 63 64 public void elideStartUpFromList() { 65 test( 66 (a) -> assertCommandOutputContains(a, "123", "==> 123"), 67 (a) -> assertCommandCheckOutput(a, "/list", (s) -> { 68 int cnt; 69 try (Scanner scanner = new Scanner(s)) { 70 cnt = 0; 71 while (scanner.hasNextLine()) { 72 String line = scanner.nextLine(); 73 if (!line.trim().isEmpty()) { 74 ++cnt; 75 } 76 } 77 } 78 assertEquals(cnt, 1, "Expected only one listed line"); 79 }) 80 ); 81 } 82 83 public void elideStartUpFromSave() throws IOException { 84 Compiler compiler = new Compiler(); 85 Path path = compiler.getPath("myfile"); 86 test( 87 (a) -> assertCommandOutputContains(a, "123", "==> 123"), 88 (a) -> assertCommand(a, "/save " + path.toString(), "") 89 ); 90 try (Stream<String> lines = Files.lines(path)) { 91 assertEquals(lines.count(), 1, "Expected only one saved line"); 92 } 93 } 94 95 public void testInterrupt() { 96 ReplTest interrupt = (a) -> assertCommand(a, "\u0003", ""); 97 for (String s : new String[] { "", "\u0003" }) { 98 test(false, new String[]{"--no-startup"}, 99 (a) -> assertCommand(a, "int a = 2 +" + s, ""), 100 interrupt, 101 (a) -> assertCommand(a, "int a\u0003", ""), 102 (a) -> assertCommand(a, "int a = 2 + 2\u0003", ""), 103 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 104 (a) -> evaluateExpression(a, "int", "2", "2"), 105 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 106 (a) -> assertCommand(a, "void f() {", ""), 107 (a) -> assertCommand(a, "int q = 10;" + s, ""), 108 interrupt, 109 (a) -> assertCommand(a, "void f() {}\u0003", ""), 110 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 111 (a) -> assertMethod(a, "int f() { return 0; }", "()int", "f"), 112 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 113 (a) -> assertCommand(a, "class A {" + s, ""), 114 interrupt, 115 (a) -> assertCommand(a, "class A {}\u0003", ""), 116 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 117 (a) -> assertClass(a, "interface A {}", "interface", "A"), 118 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 119 (a) -> assertCommand(a, "import java.util.stream." + s, ""), 120 interrupt, 121 (a) -> assertCommand(a, "import java.util.stream.\u0003", ""), 122 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 123 (a) -> assertImport(a, "import java.util.stream.Stream", "", "java.util.stream.Stream"), 124 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 125 ); 126 } 127 } 128 129 private final Object lock = new Object(); 130 private PrintWriter out; 131 private boolean isStopped; 132 private Thread t; 133 private void assertStop(boolean after, String cmd, String output) { 134 if (!after) { 135 isStopped = false; 136 StringWriter writer = new StringWriter(); 137 out = new PrintWriter(writer); 138 setCommandInput(cmd + "\n"); 139 t = new Thread(() -> { 140 try { 141 // no chance to know whether cmd is being evaluated 142 Thread.sleep(5000); 143 } catch (InterruptedException ignored) { 144 } 145 int i = 1; 146 int n = 30; 147 synchronized (lock) { 148 do { 149 setCommandInput("\u0003"); 150 if (!isStopped) { 151 out.println("Not stopped. Try again: " + i); 152 try { 153 lock.wait(1000); 154 } catch (InterruptedException ignored) { 155 } 156 } 157 } while (i++ < n && !isStopped); 158 if (!isStopped) { 159 System.err.println(writer.toString()); 160 fail("Evaluation was not stopped: '" + cmd + "'"); 161 } 162 } 163 }); 164 t.start(); 165 } else { 166 synchronized (lock) { 167 out.println("Evaluation was stopped successfully: '" + cmd + "'"); 168 isStopped = true; 169 lock.notify(); 170 } 171 try { 172 t.join(); 173 t = null; 174 } catch (InterruptedException ignored) { 175 } 176 assertOutput(getCommandOutput(), "", "command"); 177 assertOutput(getCommandErrorOutput(), "", "command error"); 178 assertOutput(getUserOutput().trim(), output, "user"); 179 assertOutput(getUserErrorOutput(), "", "user error"); 180 } 181 } 182 183 public void testStop() { 184 test( 185 (a) -> assertStop(a, "while (true) {}", ""), 186 (a) -> assertStop(a, "while (true) { try { Thread.sleep(100); } catch (InterruptedException ex) { } }", "") 187 ); 188 } 189 190 public void testRerun() { 191 test(false, new String[] {"--no-startup"}, 192 (a) -> assertCommand(a, "/0", "| No snippet with ID: 0"), 193 (a) -> assertCommand(a, "/5", "| No snippet with ID: 5") 194 ); 195 String[] codes = new String[] { 196 "int a = 0;", // var 197 "class A {}", // class 198 "void f() {}", // method 199 "bool b;", // active failed 200 "void g() { h(); }", // active corralled 201 }; 202 List<ReplTest> tests = new ArrayList<>(); 203 for (String s : codes) { 204 tests.add((a) -> assertCommand(a, s, null)); 205 } 206 // Test /1 through /5 -- assure references are correct 207 for (int i = 0; i < codes.length; ++i) { 208 final int finalI = i; 209 Consumer<String> check = (s) -> { 210 String[] ss = s.split("\n"); 211 assertEquals(ss[0], codes[finalI]); 212 assertTrue(ss.length > 1, s); 213 }; 214 tests.add((a) -> assertCommandCheckOutput(a, "/" + (finalI + 1), check)); 215 } 216 // Test /-1 ... note that the snippets added by history must be stepped over 217 for (int i = 0; i < codes.length; ++i) { 218 final int finalI = i; 219 Consumer<String> check = (s) -> { 220 String[] ss = s.split("\n"); 221 assertEquals(ss[0], codes[codes.length - finalI - 1]); 222 assertTrue(ss.length > 1, s); 223 }; 224 tests.add((a) -> assertCommandCheckOutput(a, "/-" + (2 * finalI + 1), check)); 225 } 226 tests.add((a) -> assertCommandCheckOutput(a, "/!", assertStartsWith("int a = 0;"))); 227 test(false, new String[]{"--no-startup"}, 228 tests.toArray(new ReplTest[tests.size()])); 229 } 230 231 public void test8142447() { 232 Function<String, BiFunction<String, Integer, ReplTest>> assertRerun = cmd -> (code, assertionCount) -> 233 (a) -> assertCommandCheckOutput(a, cmd, s -> { 234 String[] ss = s.split("\n"); 235 assertEquals(ss[0], code); 236 loadVariable(a, "int", "assertionCount", Integer.toString(assertionCount), Integer.toString(assertionCount)); 237 }); 238 ReplTest assertVariables = (a) -> assertCommandCheckOutput(a, "/v", assertVariables()); 239 240 Compiler compiler = new Compiler(); 241 Path startup = compiler.getPath("StartupFileOption/startup.txt"); 242 compiler.writeToFile(startup, "int assertionCount = 0;\n" + // id: s1 243 "void add(int n) { assertionCount += n; }"); 244 test(new String[]{"--startup", startup.toString()}, 245 (a) -> assertCommand(a, "add(1)", ""), // id: 1 246 (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals(s.split("\n")[0], "| Error:")), // id: e1 247 (a) -> assertVariable(a, "int", "ONE", "1", "1"), 248 assertRerun.apply("/1").apply("add(1)", 2), assertVariables, 249 assertRerun.apply("/e1").apply("add(ONE)", 3), assertVariables, 250 assertRerun.apply("/s1").apply("int assertionCount = 0;", 0), assertVariables 251 ); 252 253 test(false, new String[] {"--no-startup"}, 254 (a) -> assertCommand(a, "/s1", "| No snippet with ID: s1"), 255 (a) -> assertCommand(a, "/1", "| No snippet with ID: 1"), 256 (a) -> assertCommand(a, "/e1", "| No snippet with ID: e1") 257 ); 258 } 259 260 public void testClasspathDirectory() { 261 Compiler compiler = new Compiler(); 262 Path outDir = Paths.get("testClasspathDirectory"); 263 compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }"); 264 Path classpath = compiler.getPath(outDir); 265 test( 266 (a) -> assertCommand(a, "/env --class-path " + classpath, 267 "| Setting new options and restoring state."), 268 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") 269 ); 270 test(new String[] { "--class-path", classpath.toString() }, 271 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") 272 ); 273 } 274 275 public void testEnvInStartUp() { 276 Compiler compiler = new Compiler(); 277 Path outDir = Paths.get("testClasspathDirectory"); 278 compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }"); 279 Path classpath = compiler.getPath(outDir); 280 Path sup = compiler.getPath("startup.jsh"); 281 compiler.writeToFile(sup, 282 "int xxx;\n" + 283 "/env -class-path " + classpath + "\n" + 284 "int aaa = 735;\n" 285 ); 286 test( 287 (a) -> assertCommand(a, "/set start -retain " + sup, ""), 288 (a) -> assertCommand(a, "/reset", 289 "| Resetting state."), 290 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A"), 291 (a) -> assertCommand(a, "aaa", "aaa ==> 735") 292 ); 293 test( 294 (a) -> assertCommandOutputContains(a, "/env", "--class-path"), 295 (a) -> assertCommandOutputContains(a, "xxx", "cannot find symbol", "variable xxx"), 296 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A"), 297 (a) -> assertCommand(a, "aaa", "aaa ==> 735") 298 ); 299 } 300 301 private String makeSimpleJar() { 302 Compiler compiler = new Compiler(); 303 Path outDir = Paths.get("testClasspathJar"); 304 compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }"); 305 String jarName = "test.jar"; 306 compiler.jar(outDir, jarName, "pkg/A.class"); 307 return compiler.getPath(outDir).resolve(jarName).toString(); 308 } 309 310 public void testClasspathJar() { 311 String jarPath = makeSimpleJar(); 312 test( 313 (a) -> assertCommand(a, "/env --class-path " + jarPath, 314 "| Setting new options and restoring state."), 315 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") 316 ); 317 test(new String[] { "--class-path", jarPath }, 318 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A") 319 ); 320 } 321 322 public void testClasspathUserHomeExpansion() { 323 String jarPath = makeSimpleJar(); 324 String tilde = "~" + File.separator; 325 test( 326 (a) -> assertCommand(a, "/env --class-path " + tilde + "forblato", 327 "| File '" + Paths.get(System.getProperty("user.home"), "forblato").toString() 328 + "' for '--class-path' is not found."), 329 (a) -> assertCommand(a, "/env --class-path " + jarPath + File.pathSeparator 330 + tilde + "forblato", 331 "| File '" + Paths.get(System.getProperty("user.home"), "forblato").toString() 332 + "' for '--class-path' is not found.") 333 ); 334 } 335 336 public void testBadClasspath() { 337 String jarPath = makeSimpleJar(); 338 Compiler compiler = new Compiler(); 339 Path t1 = compiler.getPath("whatever/thing.zip"); 340 compiler.writeToFile(t1, ""); 341 Path t2 = compiler.getPath("whatever/thing.jmod"); 342 compiler.writeToFile(t2, ""); 343 test( 344 (a) -> assertCommand(a, "/env --class-path " + t1.toString(), 345 "| Invalid '--class-path' argument: " + t1.toString()), 346 (a) -> assertCommand(a, "/env --class-path " + jarPath + File.pathSeparator + t1.toString(), 347 "| Invalid '--class-path' argument: " + t1.toString()), 348 (a) -> assertCommand(a, "/env --class-path " + t2.toString(), 349 "| Invalid '--class-path' argument: " + t2.toString()) 350 ); 351 } 352 353 private String makeBadSourceJar() { 354 Compiler compiler = new Compiler(); 355 Path outDir = Paths.get("testClasspathJar"); 356 Path src = compiler.getPath(outDir.resolve("pkg/A.java")); 357 compiler.writeToFile(src, "package pkg; /** \u0086 */public class A { public String toString() { return \"A\"; } }"); 358 String jarName = "test.jar"; 359 compiler.jar(outDir, jarName, "pkg/A.java"); 360 return compiler.getPath(outDir).resolve(jarName).toString(); 361 } 362 363 public void testBadSourceJarClasspath() { 364 String jarPath = makeBadSourceJar(); 365 test( 366 (a) -> assertCommand(a, "/env --class-path " + jarPath, 367 "| Setting new options and restoring state."), 368 (a) -> assertCommandOutputStartsWith(a, "new pkg.A();", 369 "| Error:\n" 370 + "| cannot find symbol\n" 371 + "| symbol: class A") 372 ); 373 test(new String[]{"--class-path", jarPath}, 374 (a) -> assertCommandOutputStartsWith(a, "new pkg.A();", 375 "| Error:\n" 376 + "| cannot find symbol\n" 377 + "| symbol: class A") 378 ); 379 } 380 381 public void testModulePath() { 382 Compiler compiler = new Compiler(); 383 Path modsDir = Paths.get("mods"); 384 Path outDir = Paths.get("mods", "org.astro"); 385 compiler.compile(outDir, "package org.astro; public class World { public static String name() { return \"world\"; } }"); 386 compiler.compile(outDir, "module org.astro { exports org.astro; }"); 387 Path modsPath = compiler.getPath(modsDir); 388 test(new String[] { "--module-path", modsPath.toString(), "--add-modules", "org.astro" }, 389 (a) -> assertCommand(a, "import org.astro.World;", ""), 390 (a) -> evaluateExpression(a, "String", 391 "String.format(\"Greetings %s!\", World.name());", 392 "\"Greetings world!\"") 393 ); 394 } 395 396 public void testModulePathUserHomeExpansion() { 397 String tilde = "~" + File.separatorChar; 398 test( 399 (a) -> assertCommand(a, "/env --module-path " + tilde + "snardugol", 400 "| File '" + Paths.get(System.getProperty("user.home"), "snardugol").toString() 401 + "' for '--module-path' is not found.") 402 ); 403 } 404 405 public void testBadModulePath() { 406 Compiler compiler = new Compiler(); 407 Path t1 = compiler.getPath("whatever/thing.zip"); 408 compiler.writeToFile(t1, ""); 409 test( 410 (a) -> assertCommand(a, "/env --module-path " + t1.toString(), 411 "| Invalid '--module-path' argument: " + t1.toString()) 412 ); 413 } 414 415 public void testStartupFileOption() { 416 Compiler compiler = new Compiler(); 417 Path startup = compiler.getPath("StartupFileOption/startup.txt"); 418 compiler.writeToFile(startup, "class A { public String toString() { return \"A\"; } }"); 419 test(new String[]{"--startup", startup.toString()}, 420 (a) -> evaluateExpression(a, "A", "new A()", "A") 421 ); 422 test(new String[]{"--no-startup"}, 423 (a) -> assertCommandCheckOutput(a, "Pattern.compile(\"x+\")", assertStartsWith("| Error:\n| cannot find symbol")) 424 ); 425 test( 426 (a) -> assertCommand(a, "Pattern.compile(\"x+\")", "$1 ==> x+", "", null, "", "") 427 ); 428 } 429 430 public void testLoadingFromArgs() { 431 Compiler compiler = new Compiler(); 432 Path path = compiler.getPath("loading.repl"); 433 compiler.writeToFile(path, "int a = 10; double x = 20; double a = 10;"); 434 test(new String[] { path.toString() }, 435 (a) -> assertCommand(a, "x", "x ==> 20.0"), 436 (a) -> assertCommand(a, "a", "a ==> 10.0") 437 ); 438 } 439 440 public void testReset() { 441 test( 442 (a) -> assertReset(a, "/res"), 443 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 444 (a) -> assertVariable(a, "int", "x"), 445 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 446 (a) -> assertMethod(a, "void f() { }", "()void", "f"), 447 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 448 (a) -> assertClass(a, "class A { }", "class", "A"), 449 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 450 (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 451 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()), 452 (a) -> assertReset(a, "/reset"), 453 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 454 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 455 (a) -> assertCommandCheckOutput(a, "/types", assertClasses()), 456 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 457 ); 458 } 459 460 public void testOpen() { 461 Compiler compiler = new Compiler(); 462 Path path = compiler.getPath("testOpen.repl"); 463 compiler.writeToFile(path, 464 "int a = 10;\ndouble x = 20;\ndouble a = 10;\n" + 465 "class A { public String toString() { return \"A\"; } }\nimport java.util.stream.*;"); 466 for (String s : new String[]{"/o", "/open"}) { 467 test( 468 (a) -> assertCommand(a, s + " " + path.toString(), ""), 469 (a) -> assertCommand(a, "a", "a ==> 10.0"), 470 (a) -> evaluateExpression(a, "A", "new A();", "A"), 471 (a) -> evaluateExpression(a, "long", "Stream.of(\"A\").count();", "1"), 472 (a) -> { 473 loadVariable(a, "double", "x", "20.0", "20.0"); 474 loadVariable(a, "double", "a", "10.0", "10.0"); 475 loadVariable(a, "A", "$7", "new A();", "A"); 476 loadVariable(a, "long", "$8", "Stream.of(\"A\").count();", "1"); 477 loadClass(a, "class A { public String toString() { return \"A\"; } }", 478 "class", "A"); 479 loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*"); 480 assertCommandCheckOutput(a, "/types", assertClasses()); 481 }, 482 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 483 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 484 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 485 ); 486 Path unknown = compiler.getPath("UNKNOWN.repl"); 487 test( 488 (a) -> assertCommand(a, s + " " + unknown, 489 "| File '" + unknown + "' for '/open' is not found.") 490 ); 491 } 492 } 493 494 public void testOpenResource() { 495 test( 496 (a) -> assertCommand(a, "/open PRINTING", ""), 497 (a) -> assertCommandOutputContains(a, "/list", 498 "void println", "System.out.printf"), 499 (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)", 500 "", "", null, "3.14", "") 501 ); 502 } 503 504 public void testSave() throws IOException { 505 Compiler compiler = new Compiler(); 506 Path path = compiler.getPath("testSave.repl"); 507 { 508 List<String> list = Arrays.asList( 509 "int a;", 510 "class A { public String toString() { return \"A\"; } }" 511 ); 512 test( 513 (a) -> assertVariable(a, "int", "a"), 514 (a) -> assertCommand(a, "()", null, null, null, "", ""), 515 (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), 516 (a) -> assertCommand(a, "/save " + path.toString(), "") 517 ); 518 assertEquals(Files.readAllLines(path), list); 519 } 520 { 521 List<String> output = new ArrayList<>(); 522 test( 523 (a) -> assertCommand(a, "int a;", null), 524 (a) -> assertCommand(a, "()", null, null, null, "", ""), 525 (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), 526 (a) -> assertCommandCheckOutput(a, "/list -all", (out) -> 527 output.addAll(Stream.of(out.split("\n")) 528 .filter(str -> !str.isEmpty()) 529 .map(str -> str.substring(str.indexOf(':') + 2)) 530 .filter(str -> !str.startsWith("/")) 531 .collect(Collectors.toList()))), 532 (a) -> assertCommand(a, "/save -all " + path.toString(), "") 533 ); 534 assertEquals(Files.readAllLines(path), output); 535 } 536 { 537 List<String> output = new ArrayList<>(); 538 test( 539 (a) -> assertCommand(a, "int a;", null), 540 (a) -> assertCommand(a, "int b;", null), 541 (a) -> assertCommand(a, "int c;", null), 542 (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), 543 (a) -> assertCommandCheckOutput(a, "/list b c a A", (out) -> 544 output.addAll(Stream.of(out.split("\n")) 545 .filter(str -> !str.isEmpty()) 546 .map(str -> str.substring(str.indexOf(':') + 2)) 547 .filter(str -> !str.startsWith("/")) 548 .collect(Collectors.toList()))), 549 (a) -> assertCommand(a, "/save 2-3 1 4 " + path.toString(), "") 550 ); 551 assertEquals(Files.readAllLines(path), output); 552 } 553 { 554 List<String> output = new ArrayList<>(); 555 test( 556 (a) -> assertVariable(a, "int", "a"), 557 (a) -> assertCommand(a, "()", null, null, null, "", ""), 558 (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), 559 (a) -> assertCommandCheckOutput(a, "/history", (out) -> 560 output.addAll(Stream.of(out.split("\n")) 561 .filter(str -> !str.isEmpty()) 562 .collect(Collectors.toList()))), 563 (a) -> assertCommand(a, "/save -history " + path.toString(), "") 564 ); 565 output.add("/save -history " + path.toString()); 566 assertEquals(Files.readAllLines(path), output); 567 } 568 } 569 570 public void testStartRetain() { 571 Compiler compiler = new Compiler(); 572 Path startUpFile = compiler.getPath("startUp.txt"); 573 test( 574 (a) -> assertVariable(a, "int", "a"), 575 (a) -> assertVariable(a, "double", "b", "10", "10.0"), 576 (a) -> assertMethod(a, "void f() {}", "()V", "f"), 577 (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), 578 (a) -> assertCommand(a, "/save " + startUpFile.toString(), null), 579 (a) -> assertCommand(a, "/set start -retain " + startUpFile.toString(), null) 580 ); 581 Path unknown = compiler.getPath("UNKNOWN"); 582 test( 583 (a) -> assertCommandOutputStartsWith(a, "/set start -retain " + unknown.toString(), 584 "| File '" + unknown + "' for '/set start' is not found.") 585 ); 586 test(false, new String[0], 587 (a) -> { 588 loadVariable(a, "int", "a"); 589 loadVariable(a, "double", "b", "10.0", "10.0"); 590 loadMethod(a, "void f() {}", "()void", "f"); 591 loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*"); 592 assertCommandCheckOutput(a, "/types", assertClasses()); 593 }, 594 (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), 595 (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()), 596 (a) -> assertCommandCheckOutput(a, "/imports", assertImports()) 597 ); 598 } 599 600 public void testStartSave() throws IOException { 601 Compiler compiler = new Compiler(); 602 Path startSave = compiler.getPath("startSave.txt"); 603 test(a -> assertCommand(a, "/save -start " + startSave.toString(), null)); 604 List<String> lines = Files.lines(startSave) 605 .filter(s -> !s.isEmpty()) 606 .collect(Collectors.toList()); 607 assertEquals(lines, START_UP); 608 } 609 610 public void testConstrainedUpdates() { 611 test( 612 a -> assertClass(a, "class XYZZY { }", "class", "XYZZY"), 613 a -> assertVariable(a, "XYZZY", "xyzzy"), 614 a -> assertCommandCheckOutput(a, "import java.util.stream.*", 615 (out) -> assertTrue(out.trim().isEmpty(), "Expected no output, got: " + out)) 616 ); 617 } 618 619 public void testRemoteExit() { 620 test( 621 a -> assertVariable(a, "int", "x"), 622 a -> assertCommandCheckOutput(a, "/vars", assertVariables()), 623 a -> assertCommandOutputContains(a, "System.exit(5);", "terminated"), 624 a -> assertCommandCheckOutput(a, "/vars", s -> 625 assertTrue(s.trim().isEmpty(), s)), 626 a -> assertMethod(a, "void f() { }", "()void", "f"), 627 a -> assertCommandCheckOutput(a, "/methods", assertMethods()) 628 ); 629 } 630 631 public void testFeedbackNegative() { 632 test(a -> assertCommandCheckOutput(a, "/set feedback aaaa", 633 assertStartsWith("| Does not match any current feedback mode"))); 634 } 635 636 public void testFeedbackSilent() { 637 for (String off : new String[]{"s", "silent"}) { 638 test( 639 a -> assertCommand(a, "/set feedback " + off, ""), 640 a -> assertCommand(a, "int a", ""), 641 a -> assertCommand(a, "void f() {}", ""), 642 a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), 643 a -> assertCommandCheckOutput(a, "static void f() {}", assertStartsWith("| Warning:")) 644 ); 645 } 646 } 647 648 public void testFeedbackNormal() { 649 Compiler compiler = new Compiler(); 650 Path testNormalFile = compiler.getPath("testConciseNormal"); 651 String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; 652 String[] sources2 = new String[] {"int a //again", "void f() {int y = 4;}", "class A {} //again", "a = 10"}; 653 String[] output = new String[] { 654 "a ==> 0", 655 "| created method f()", 656 "| created class A", 657 "a ==> 10" 658 }; 659 compiler.writeToFile(testNormalFile, sources2); 660 for (String feedback : new String[]{"/set fe", "/set feedback"}) { 661 for (String feedbackState : new String[]{"n", "normal"}) { 662 test( 663 a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: normal"), 664 a -> assertCommand(a, sources[0], output[0]), 665 a -> assertCommand(a, sources[1], output[1]), 666 a -> assertCommand(a, sources[2], output[2]), 667 a -> assertCommand(a, sources[3], output[3]), 668 a -> assertCommand(a, "/o " + testNormalFile.toString(), "") 669 ); 670 } 671 } 672 } 673 674 public void testVarsWithNotActive() { 675 test( 676 a -> assertVariable(a, "Blath", "x"), 677 a -> assertCommandOutputContains(a, "/var -all", "(not-active)") 678 ); 679 } 680 681 public void testHistoryReference() { 682 test(false, new String[]{"--no-startup"}, 683 a -> assertCommand(a, "System.err.println(99)", "", "", null, "", "99\n"), 684 a -> assertCommand(a, "/exit", "") 685 ); 686 test(false, new String[]{"--no-startup"}, 687 a -> assertCommand(a, "System.err.println(1)", "", "", null, "", "1\n"), 688 a -> assertCommand(a, "System.err.println(2)", "", "", null, "", "2\n"), 689 a -> assertCommand(a, "/-2", "System.err.println(1)", "", null, "", "1\n"), 690 a -> assertCommand(a, "/history", 691 "/debug 0\n" + 692 "System.err.println(1)\n" + 693 "System.err.println(2)\n" + 694 "System.err.println(1)\n" + 695 "/history\n"), 696 a -> assertCommand(a, "/history -all", 697 "/debug 0\n" + 698 "System.err.println(99)\n" + 699 "/exit\n" + 700 "/debug 0\n" + 701 "System.err.println(1)\n" + 702 "System.err.println(2)\n" + 703 "System.err.println(1)\n" + 704 "/history\n" + 705 "/history -all\n"), 706 a -> assertCommand(a, "/-2", "System.err.println(2)", "", null, "", "2\n"), 707 a -> assertCommand(a, "/!", "System.err.println(2)", "", null, "", "2\n"), 708 a -> assertCommand(a, "/2", "System.err.println(2)", "", null, "", "2\n"), 709 a -> assertCommand(a, "/1", "System.err.println(1)", "", null, "", "1\n") 710 ); 711 } 712 713 public void testRerunIdRange() { 714 Compiler compiler = new Compiler(); 715 Path startup = compiler.getPath("rangeStartup"); 716 String[] startupSources = new String[] { 717 "boolean go = false", 718 "void println(String s) { if (go) System.out.println(s); }", 719 "void println(int i) { if (go) System.out.println(i); }", 720 "println(\"s4\")", 721 "println(\"s5\")", 722 "println(\"s6\")" 723 }; 724 String[] sources = new String[] { 725 "frog", 726 "go = true", 727 "println(2)", 728 "println(3)", 729 "println(4)", 730 "querty" 731 }; 732 compiler.writeToFile(startup, startupSources); 733 test(false, new String[]{"--startup", startup.toString()}, 734 a -> assertCommandOutputStartsWith(a, sources[0], "| Error:"), 735 a -> assertCommand(a, sources[1], "go ==> true", "", null, "", ""), 736 a -> assertCommand(a, sources[2], "", "", null, "2\n", ""), 737 a -> assertCommand(a, sources[3], "", "", null, "3\n", ""), 738 a -> assertCommand(a, sources[4], "", "", null, "4\n", ""), 739 a -> assertCommandOutputStartsWith(a, sources[5], "| Error:"), 740 a -> assertCommand(a, "/3", "println(3)", "", null, "3\n", ""), 741 a -> assertCommand(a, "/s4", "println(\"s4\")", "", null, "s4\n", ""), 742 a -> assertCommandOutputStartsWith(a, "/e1", "frog\n| Error:"), 743 a -> assertCommand(a, "/2-4", 744 "println(2)\nprintln(3)\nprintln(4)", 745 "", null, "2\n3\n4\n", ""), 746 a -> assertCommand(a, "/s4-s6", 747 startupSources[3] + "\n" +startupSources[4] + "\n" +startupSources[5], 748 "", null, "s4\ns5\ns6\n", ""), 749 a -> assertCommand(a, "/s4-4", null, 750 "", null, "s4\ns5\ns6\n2\n3\n4\n", ""), 751 a -> assertCommandCheckOutput(a, "/e1-e2", 752 s -> { 753 assertTrue(s.trim().startsWith("frog\n| Error:"), 754 "Output: \'" + s + "' does not start with: " + "| Error:"); 755 assertTrue(s.trim().lastIndexOf("| Error:") > 10, 756 "Output: \'" + s + "' does not have second: " + "| Error:"); 757 }), 758 a -> assertCommand(a, "/4 s4 2", 759 "println(4)\nprintln(\"s4\")\nprintln(2)", 760 "", null, "4\ns4\n2\n", ""), 761 a -> assertCommand(a, "/s5 2-4 3", 762 "println(\"s5\")\nprintln(2)\nprintln(3)\nprintln(4)\nprintln(3)", 763 "", null, "s5\n2\n3\n4\n3\n", ""), 764 a -> assertCommand(a, "/2 ff", "| No such snippet: ff"), 765 a -> assertCommand(a, "/4-2", "| End of snippet range less than start: 4 - 2"), 766 a -> assertCommand(a, "/s5-s3", "| End of snippet range less than start: s5 - s3"), 767 a -> assertCommand(a, "/4-s5", "| End of snippet range less than start: 4 - s5") 768 ); 769 } 770 771 @Test(enabled = false) // TODO 8158197 772 public void testHeadlessEditPad() { 773 String prevHeadless = System.getProperty("java.awt.headless"); 774 try { 775 System.setProperty("java.awt.headless", "true"); 776 test( 777 (a) -> assertCommandOutputStartsWith(a, "/edit printf", "| Cannot launch editor -- unexpected exception:") 778 ); 779 } finally { 780 System.setProperty("java.awt.headless", prevHeadless==null? "false" : prevHeadless); 781 } 782 } 783 784 public void testAddExports() { 785 test(false, new String[]{"--no-startup"}, 786 a -> assertCommandOutputStartsWith(a, "import jdk.internal.misc.VM;", "| Error:") 787 ); 788 test(false, new String[]{"--no-startup", 789 "-R--add-exports", "-Rjava.base/jdk.internal.misc=ALL-UNNAMED", 790 "-C--add-exports", "-Cjava.base/jdk.internal.misc=ALL-UNNAMED"}, 791 a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"), 792 a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n") 793 ); 794 test(false, new String[]{"--no-startup", "--add-exports", "java.base/jdk.internal.misc"}, 795 a -> assertImport(a, "import jdk.internal.misc.VM;", "", "jdk.internal.misc.VM"), 796 a -> assertCommand(a, "System.err.println(VM.isBooted())", "", "", null, "", "true\n") 797 ); 798 } 799 800 }