8247403: JShell: No custom input (e.g. from GUI) possible with JavaShellToolBuilder

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2021-05-31 09:25:16 +00:00
parent 64f0f68958
commit 2c8e94f680
14 changed files with 247 additions and 29 deletions

View File

@ -4157,7 +4157,7 @@ public class LineReaderImpl implements LineReader, Flushable
} else } else
sb.append(ch); sb.append(ch);
} }
if (padToWidth > cols) { if (padToWidth > cols && padToWidth > 0) {
int padCharCols = WCWidth.wcwidth(padChar); int padCharCols = WCWidth.wcwidth(padChar);
int padCount = (padToWidth - cols) / padCharCols; int padCount = (padToWidth - cols) / padCharCols;
sb = padPartString; sb = padPartString;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -47,6 +47,7 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -103,8 +104,8 @@ class ConsoleIOContext extends IOContext {
String prefix = ""; String prefix = "";
ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout) throws Exception { ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout,
this.allowIncompleteInputs = Boolean.getBoolean("jshell.test.allow.incomplete.inputs"); boolean interactive) throws Exception {
this.repl = repl; this.repl = repl;
Map<String, Object> variables = new HashMap<>(); Map<String, Object> variables = new HashMap<>();
this.input = new StopDetectingInputStream(() -> repl.stop(), this.input = new StopDetectingInputStream(() -> repl.stop(),
@ -116,8 +117,20 @@ class ConsoleIOContext extends IOContext {
} }
}; };
Terminal terminal; Terminal terminal;
if (System.getProperty("test.jdk") != null) { boolean allowIncompleteInputs = Boolean.getBoolean("jshell.test.allow.incomplete.inputs");
terminal = new TestTerminal(nonBlockingInput, cmdout); Consumer<LineReaderImpl> setupReader = r -> {};
if (cmdin != System.in) {
if (System.getProperty("test.jdk") != null) {
terminal = new TestTerminal(nonBlockingInput, cmdout);
} else {
Size size = null;
terminal = new ProgrammaticInTerminal(nonBlockingInput, cmdout, interactive,
size);
if (!interactive) {
setupReader = r -> r.unsetOpt(Option.BRACKETED_PASTE);
allowIncompleteInputs = true;
}
}
input.setInputStream(cmdin); input.setInputStream(cmdin);
} else { } else {
terminal = TerminalBuilder.builder().inputStreamWrapper(in -> { terminal = TerminalBuilder.builder().inputStreamWrapper(in -> {
@ -125,6 +138,7 @@ class ConsoleIOContext extends IOContext {
return nonBlockingInput; return nonBlockingInput;
}).build(); }).build();
} }
this.allowIncompleteInputs = allowIncompleteInputs;
originalAttributes = terminal.getAttributes(); originalAttributes = terminal.getAttributes();
Attributes noIntr = new Attributes(originalAttributes); Attributes noIntr = new Attributes(originalAttributes);
noIntr.setControlChar(ControlChar.VINTR, 0); noIntr.setControlChar(ControlChar.VINTR, 0);
@ -179,10 +193,11 @@ class ConsoleIOContext extends IOContext {
} }
}; };
setupReader.accept(reader);
reader.setOpt(Option.DISABLE_EVENT_EXPANSION); reader.setOpt(Option.DISABLE_EVENT_EXPANSION);
reader.setParser((line, cursor, context) -> { reader.setParser((line, cursor, context) -> {
if (!allowIncompleteInputs && !repl.isComplete(line)) { if (!ConsoleIOContext.this.allowIncompleteInputs && !repl.isComplete(line)) {
int pendingBraces = countPendingOpenBraces(line); int pendingBraces = countPendingOpenBraces(line);
throw new EOFError(cursor, cursor, line, null, pendingBraces, null); throw new EOFError(cursor, cursor, line, null, pendingBraces, null);
} }
@ -230,7 +245,7 @@ class ConsoleIOContext extends IOContext {
this.prefix = prefix; this.prefix = prefix;
try { try {
in.setVariable(LineReader.SECONDARY_PROMPT_PATTERN, continuationPrompt); in.setVariable(LineReader.SECONDARY_PROMPT_PATTERN, continuationPrompt);
return in.readLine(firstLinePrompt); return in.readLine(firstLine ? firstLinePrompt : continuationPrompt);
} catch (UserInterruptException ex) { } catch (UserInterruptException ex) {
throw (InputInterruptedException) new InputInterruptedException().initCause(ex); throw (InputInterruptedException) new InputInterruptedException().initCause(ex);
} catch (EndOfFileException ex) { } catch (EndOfFileException ex) {
@ -1276,28 +1291,31 @@ class ConsoleIOContext extends IOContext {
return in.getHistory(); return in.getHistory();
} }
private static final class TestTerminal extends LineDisciplineTerminal { private static class ProgrammaticInTerminal extends LineDisciplineTerminal {
private static final int DEFAULT_HEIGHT = 24; protected static final int DEFAULT_HEIGHT = 24;
private final NonBlockingReader inputReader; private final NonBlockingReader inputReader;
private final Size bufferSize;
public TestTerminal(InputStream input, OutputStream output) throws Exception { public ProgrammaticInTerminal(InputStream input, OutputStream output,
super("test", "ansi", output, Charset.forName("UTF-8")); boolean interactive, Size size) throws Exception {
this(input, output, interactive ? "ansi" : "dumb",
size != null ? size : new Size(80, DEFAULT_HEIGHT),
size != null ? size
: interactive ? new Size(80, DEFAULT_HEIGHT)
: new Size(Integer.MAX_VALUE - 1, DEFAULT_HEIGHT));
}
protected ProgrammaticInTerminal(InputStream input, OutputStream output,
String terminal, Size size, Size bufferSize) throws Exception {
super("non-system-in", terminal, output, Charset.forName("UTF-8"));
this.inputReader = NonBlocking.nonBlocking(getName(), input, encoding()); this.inputReader = NonBlocking.nonBlocking(getName(), input, encoding());
Attributes a = new Attributes(getAttributes()); Attributes a = new Attributes(getAttributes());
a.setLocalFlag(LocalFlag.ECHO, false); a.setLocalFlag(LocalFlag.ECHO, false);
setAttributes(attributes); setAttributes(attributes);
int h = DEFAULT_HEIGHT; setSize(size);
try { this.bufferSize = bufferSize;
String hp = System.getProperty("test.terminal.height");
if (hp != null && !hp.isEmpty()) {
h = Integer.parseInt(hp);
}
} catch (Throwable ex) {
// ignore
}
setSize(new Size(80, h));
} }
@Override @Override
@ -1312,6 +1330,31 @@ class ConsoleIOContext extends IOContext {
inputReader.close(); inputReader.close();
} }
@Override
public Size getBufferSize() {
return bufferSize;
}
}
private static final class TestTerminal extends ProgrammaticInTerminal {
private static Size computeSize() {
int h = DEFAULT_HEIGHT;
try {
String hp = System.getProperty("test.terminal.height");
if (hp != null && !hp.isEmpty() && System.getProperty("test.jdk") != null) {
h = Integer.parseInt(hp);
}
} catch (Throwable ex) {
// ignore
}
return new Size(80, h);
}
public TestTerminal(InputStream input, OutputStream output) throws Exception {
this(input, output, computeSize());
}
private TestTerminal(InputStream input, OutputStream output, Size size) throws Exception {
super(input, output, "ansi", size, size);
}
} }
private static final class CompletionState { private static final class CompletionState {

View File

@ -138,6 +138,8 @@ import static jdk.internal.jshell.tool.ContinuousCompletionProvider.STARTSWITH_M
*/ */
public class JShellTool implements MessageHandler { public class JShellTool implements MessageHandler {
private static String PROMPT = "\u0005";
private static String CONTINUATION_PROMPT = "\u0006";
private static final Pattern LINEBREAK = Pattern.compile("\\R"); private static final Pattern LINEBREAK = Pattern.compile("\\R");
private static final Pattern ID = Pattern.compile("[se]?\\d+([-\\s].*)?"); private static final Pattern ID = Pattern.compile("[se]?\\d+([-\\s].*)?");
private static final Pattern RERUN_ID = Pattern.compile("/" + ID.pattern()); private static final Pattern RERUN_ID = Pattern.compile("/" + ID.pattern());
@ -158,6 +160,7 @@ public class JShellTool implements MessageHandler {
final PersistentStorage prefs; final PersistentStorage prefs;
final Map<String, String> envvars; final Map<String, String> envvars;
final Locale locale; final Locale locale;
final boolean interactiveTerminal;
final Feedback feedback = new Feedback(); final Feedback feedback = new Feedback();
@ -177,7 +180,8 @@ public class JShellTool implements MessageHandler {
JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr, JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr,
PrintStream console, PrintStream console,
InputStream userin, PrintStream userout, PrintStream usererr, InputStream userin, PrintStream userout, PrintStream usererr,
PersistentStorage prefs, Map<String, String> envvars, Locale locale) { PersistentStorage prefs, Map<String, String> envvars, Locale locale,
boolean interactiveTerminal) {
this.cmdin = cmdin; this.cmdin = cmdin;
this.cmdout = cmdout; this.cmdout = cmdout;
this.cmderr = cmderr; this.cmderr = cmderr;
@ -193,6 +197,7 @@ public class JShellTool implements MessageHandler {
this.prefs = prefs; this.prefs = prefs;
this.envvars = envvars; this.envvars = envvars;
this.locale = locale; this.locale = locale;
this.interactiveTerminal = interactiveTerminal;
} }
private ResourceBundle versionRB = null; private ResourceBundle versionRB = null;
@ -974,7 +979,7 @@ public class JShellTool implements MessageHandler {
}; };
Runtime.getRuntime().addShutdownHook(shutdownHook); Runtime.getRuntime().addShutdownHook(shutdownHook);
// execute from user input // execute from user input
try (IOContext in = new ConsoleIOContext(this, cmdin, console)) { try (IOContext in = new ConsoleIOContext(this, cmdin, console, interactiveTerminal)) {
int indent; int indent;
try { try {
String indentValue = indent(); String indentValue = indent();
@ -1256,12 +1261,12 @@ public class JShellTool implements MessageHandler {
return src; return src;
} }
String firstLinePrompt = interactive() String firstLinePrompt = interactive()
? testPrompt ? " \005" ? testPrompt ? PROMPT
: feedback.getPrompt(currentNameSpace.tidNext()) : feedback.getPrompt(currentNameSpace.tidNext())
: "" // Non-interactive -- no prompt : "" // Non-interactive -- no prompt
; ;
String continuationPrompt = interactive() String continuationPrompt = interactive()
? testPrompt ? " \006" ? testPrompt ? CONTINUATION_PROMPT
: feedback.getContinuationPrompt(currentNameSpace.tidNext()) : feedback.getContinuationPrompt(currentNameSpace.tidNext())
: "" // Non-interactive -- no prompt : "" // Non-interactive -- no prompt
; ;

View File

@ -51,6 +51,7 @@ public class JShellToolBuilder implements JavaShellToolBuilder {
private PersistentStorage prefs = null; private PersistentStorage prefs = null;
private Map<String, String> vars = null; private Map<String, String> vars = null;
private Locale locale = Locale.getDefault(); private Locale locale = Locale.getDefault();
private boolean interactiveTerminal;
private boolean capturePrompt = false; private boolean capturePrompt = false;
/** /**
@ -208,6 +209,12 @@ public class JShellToolBuilder implements JavaShellToolBuilder {
return this; return this;
} }
@Override
public JavaShellToolBuilder interactiveTerminal(boolean terminal) {
this.interactiveTerminal = terminal;
return this;
}
/** /**
* Create a tool instance for testing. Not in JavaShellToolBuilder. * Create a tool instance for testing. Not in JavaShellToolBuilder.
* *
@ -221,7 +228,7 @@ public class JShellToolBuilder implements JavaShellToolBuilder {
vars = System.getenv(); vars = System.getenv();
} }
JShellTool sh = new JShellTool(cmdIn, cmdOut, cmdErr, console, userIn, JShellTool sh = new JShellTool(cmdIn, cmdOut, cmdErr, console, userIn,
userOut, userErr, prefs, vars, locale); userOut, userErr, prefs, vars, locale, interactiveTerminal);
sh.testPrompt = capturePrompt; sh.testPrompt = capturePrompt;
return sh; return sh;
} }

View File

@ -183,6 +183,32 @@ public interface JavaShellToolBuilder {
*/ */
JavaShellToolBuilder promptCapture(boolean capture); JavaShellToolBuilder promptCapture(boolean capture);
/**
* Set to true to specify the inputs and outputs are connected to an interactive terminal
* that can interpret the ANSI escape codes. The characters sent to the output streams are
* assumed to be interpreted by a terminal and shown to the user, and the exact order and nature
* of characters sent to the outputs are unspecified.
*
* Set to false to specify a legacy simpler behavior whose output can be parsed by automatic
* tools.
*
* When the input stream for this Java Shell is {@code System.in}, this value is ignored,
* and the behavior is similar to specifying {@code true} in this method, but is more closely
* following the specific terminal connected to {@code System.in}.
*
* @implSpec If this method is not called, the behavior should be
* equivalent to calling {@code interactiveTerminal(false)}. The default implementation of
* this method returns {@code this}.
*
* @param terminal if {@code true}, an terminal that can interpret the ANSI escape codes is
* assumed to interpret the output. If {@code false}, a simpler output is selected.
* @return the {@code JavaShellToolBuilder} instance
* @since 17
*/
default JavaShellToolBuilder interactiveTerminal(boolean terminal) {
return this;
}
/** /**
* Run an instance of the Java shell tool as configured by the other methods * Run an instance of the Java shell tool as configured by the other methods
* in this interface. This call is not destructive, more than one call of * in this interface. This call is not destructive, more than one call of

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8247403
* @summary Verify JavaShellToolBuilder uses provided inputs
* @modules jdk.jshell
* @build KullaTesting TestingInputStream
* @run testng CustomInputToolBuilder
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import jdk.jshell.tool.JavaShellToolBuilder;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
@Test
public class CustomInputToolBuilder extends KullaTesting {
private static final String TEST_JDK = "test.jdk";
public void checkCustomInput() throws Exception {
String testJdk = System.getProperty(TEST_JDK);
try {
System.clearProperty(TEST_JDK);
doTest("System.out.println(\"read: \" + System.in.read());",
"\u0005System.out.println(\"read: \" + System.in.read());",
"read: 97",
"\u0005/exit");
doTest("1 + 1", "\u00051 + 1", "$1 ==> 2", "\u0005/exit");
doTest("for (int i = 0; i < 100; i++) {\nSystem.err.println(i);\n}\n",
"\u0005for (int i = 0; i < 100; i++) {",
"\u0006System.err.println(i);", "\u0006}",
"\u0005/exit");
StringBuilder longInput = new StringBuilder();
String constant = "1_______________1";
longInput.append(constant);
for (int i = 0; i < 100; i++) {
longInput.append(" + ");
longInput.append(constant);
}
doTest(longInput.toString(), "\u0005" + longInput);
} finally {
System.setProperty(TEST_JDK, testJdk);
}
}
private void doTest(String code, String... expectedLines) throws Exception {
doTest(false, code, expectedLines);
}
private void doTest(boolean interactiveTerminal, String code, String... expectedLines) throws Exception {
byte[] cmdInputData = (code + "\n/exit\n").getBytes();
InputStream cmdInput = new ByteArrayInputStream(cmdInputData);
InputStream userInput = new ByteArrayInputStream("a\n".getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream printOut = new PrintStream(out);
JavaShellToolBuilder.builder()
.in(cmdInput, userInput)
.out(printOut, printOut, printOut)
.interactiveTerminal(interactiveTerminal)
.promptCapture(true)
.start("--no-startup");
String actual = new String(out.toByteArray());
List<String> actualLines = Arrays.asList(actual.split("\\R"));
for (String expectedLine : expectedLines) {
assertTrue(actualLines.contains(expectedLine),
"actual:\n" + actualLines + "\n, expected:\n" + expectedLine);
}
}
public void checkInteractiveTerminal() throws Exception {
String testJdk = System.getProperty(TEST_JDK);
try {
System.clearProperty(TEST_JDK);
//note the exact format of the output is not specified here, and the test mostly validates
//the current behavior, and shows the output changes based on the interactiveTerminal setting:
doTest(true,
"System.out.println(\"read: \" + System.in.read());",
"\u001b[?2004h\u0005System.out.println(\"read: \" + System.in.read()\u001b[2D\u001b[2C)\u001b[29D\u001b[29C;",
"\u001b[?2004lread: 97",
"\u001b[?2004h\u0005/exit");
doTest(true,
"1 + 1",
"\u001b[?2004h\u00051 + 1",
"\u001b[?2004l$1 ==> 2",
"\u001b[?2004h\u0005/exit");
} finally {
System.setProperty(TEST_JDK, testJdk);
}
}
}

View File

@ -28,6 +28,7 @@
* @modules * @modules
* jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.main
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @library /tools/lib * @library /tools/lib

View File

@ -29,6 +29,7 @@
* @modules * @modules
* jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.main
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask

View File

@ -32,6 +32,7 @@
* jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.main
* jdk.internal.le/jdk.internal.org.jline.reader.impl * jdk.internal.le/jdk.internal.org.jline.reader.impl
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask

View File

@ -26,6 +26,7 @@
* @bug 8182489 * @bug 8182489
* @summary test history with multiline snippets * @summary test history with multiline snippets
* @modules * @modules
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @build UITesting * @build UITesting

View File

@ -26,6 +26,7 @@
* @bug 8166334 8188894 * @bug 8166334 8188894
* @summary test shift-tab shortcuts "fixes" * @summary test shift-tab shortcuts "fixes"
* @modules * @modules
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @build UITesting * @build UITesting

View File

@ -27,6 +27,7 @@
* @modules * @modules
* jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.main
* jdk.jshell/jdk.internal.jshell.tool:open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @library /tools/lib * @library /tools/lib

View File

@ -27,7 +27,7 @@
* @modules * @modules
* jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.main
* jdk.jshell/jdk.internal.jshell.tool * jdk.jshell/jdk.internal.jshell.tool:+open
* jdk.jshell/jdk.internal.jshell.tool.resources:open * jdk.jshell/jdk.internal.jshell.tool.resources:open
* jdk.jshell/jdk.jshell:open * jdk.jshell/jdk.jshell:open
* @library /tools/lib * @library /tools/lib

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Field;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
@ -108,6 +109,13 @@ public class UITesting {
runner.start(); runner.start();
try { try {
Class<?> jshellToolClass = Class.forName("jdk.internal.jshell.tool.JShellTool");
Field promptField = jshellToolClass.getDeclaredField("PROMPT");
promptField.setAccessible(true);
promptField.set(null, PROMPT);
Field continuationPromptField = jshellToolClass.getDeclaredField("CONTINUATION_PROMPT");
continuationPromptField.setAccessible(true);
continuationPromptField.set(null, CONTINUATION_PROMPT);
waitOutput(out, PROMPT); waitOutput(out, PROMPT);
test.test(inputSink, out); test.test(inputSink, out);
} finally { } finally {