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