8177076: jshell tool: allow non-zero /exit
8190383: JShell API: no way for the jshell tool to report exit status to provider Reviewed-by: jlahoda
This commit is contained in:
parent
60c7c6052d
commit
c0689879a7
src/jdk.jshell/share/classes/jdk
internal/jshell/tool
jshell/tool
test/langtools/jdk/jshell
@ -923,7 +923,7 @@ class ConsoleIOContext extends IOContext {
|
||||
|
||||
@Override
|
||||
public void perform(ConsoleReader in) throws IOException {
|
||||
repl.processCompleteSource("import " + type + ";");
|
||||
repl.processSource("import " + type + ";");
|
||||
in.println("Imported: " + type);
|
||||
performToVar(in, stype);
|
||||
}
|
||||
@ -1028,7 +1028,7 @@ class ConsoleIOContext extends IOContext {
|
||||
|
||||
@Override
|
||||
public void perform(ConsoleReader in) throws IOException {
|
||||
repl.processCompleteSource("import " + type + ";");
|
||||
repl.processSource("import " + type + ";");
|
||||
in.println("Imported: " + type);
|
||||
performToMethod(in, stype, codeToCursor);
|
||||
}
|
||||
@ -1052,7 +1052,7 @@ class ConsoleIOContext extends IOContext {
|
||||
|
||||
@Override
|
||||
public void perform(ConsoleReader in) throws IOException {
|
||||
repl.processCompleteSource("import " + fqn + ";");
|
||||
repl.processSource("import " + fqn + ";");
|
||||
in.println("Imported: " + fqn);
|
||||
in.redrawLine();
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package jdk.internal.jshell.tool;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
@ -81,10 +82,12 @@ import jdk.jshell.JShell;
|
||||
import jdk.jshell.JShell.Subscription;
|
||||
import jdk.jshell.MethodSnippet;
|
||||
import jdk.jshell.Snippet;
|
||||
import jdk.jshell.Snippet.Kind;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
import jdk.jshell.SnippetEvent;
|
||||
import jdk.jshell.SourceCodeAnalysis;
|
||||
import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
|
||||
import jdk.jshell.SourceCodeAnalysis.Completeness;
|
||||
import jdk.jshell.SourceCodeAnalysis.Suggestion;
|
||||
import jdk.jshell.TypeDeclSnippet;
|
||||
import jdk.jshell.UnresolvedReferenceException;
|
||||
@ -112,6 +115,7 @@ import static java.util.Arrays.asList;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND;
|
||||
import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA;
|
||||
@ -203,6 +207,7 @@ public class JShellTool implements MessageHandler {
|
||||
private boolean isCurrentlyRunningStartup = false;
|
||||
private String executionControlSpec = null;
|
||||
private EditorSetting editor = BUILT_IN_EDITOR;
|
||||
private int exitCode = 0;
|
||||
|
||||
private static final String[] EDITOR_ENV_VARS = new String[] {
|
||||
"JSHELLEDITOR", "VISUAL", "EDITOR"};
|
||||
@ -219,6 +224,7 @@ public class JShellTool implements MessageHandler {
|
||||
|
||||
static final Pattern BUILTIN_FILE_PATTERN = Pattern.compile("\\w+");
|
||||
static final String BUILTIN_FILE_PATH_FORMAT = "/jdk/jshell/tool/resources/%s.jsh";
|
||||
static final String INT_PREFIX = "int $$exit$$ = ";
|
||||
|
||||
// match anything followed by whitespace
|
||||
private static final Pattern OPTION_PRE_PATTERN =
|
||||
@ -364,6 +370,7 @@ public class JShellTool implements MessageHandler {
|
||||
.stream()
|
||||
.collect(joining(", ")));
|
||||
}
|
||||
exitCode = 1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -424,7 +431,12 @@ public class JShellTool implements MessageHandler {
|
||||
.collect(toList())
|
||||
);
|
||||
|
||||
return failed ? null : opts;
|
||||
if (failed) {
|
||||
exitCode = 1;
|
||||
return null;
|
||||
} else {
|
||||
return opts;
|
||||
}
|
||||
}
|
||||
|
||||
void addOptions(OptionKind kind, Collection<String> vals) {
|
||||
@ -537,6 +549,7 @@ public class JShellTool implements MessageHandler {
|
||||
(options.has(argS) ? 1 : 0) +
|
||||
(options.has(argV) ? 1 : 0)) > 1) {
|
||||
msg("jshell.err.opt.feedback.one");
|
||||
exitCode = 1;
|
||||
return null;
|
||||
} else if (options.has(argFeedback)) {
|
||||
feedbackMode = options.valueOf(argFeedback);
|
||||
@ -551,10 +564,12 @@ public class JShellTool implements MessageHandler {
|
||||
List<String> sts = options.valuesOf(argStart);
|
||||
if (options.has("no-startup")) {
|
||||
msg("jshell.err.opt.startup.conflict");
|
||||
exitCode = 1;
|
||||
return null;
|
||||
}
|
||||
initialStartup = Startup.fromFileList(sts, "--startup", new InitMessageHandler());
|
||||
if (initialStartup == null) {
|
||||
exitCode = 1;
|
||||
return null;
|
||||
}
|
||||
} else if (options.has(argNoStart)) {
|
||||
@ -865,13 +880,15 @@ public class JShellTool implements MessageHandler {
|
||||
*
|
||||
* @param args the command-line arguments
|
||||
* @throws Exception catastrophic fatal exception
|
||||
* @return the exit code
|
||||
*/
|
||||
public void start(String[] args) throws Exception {
|
||||
public int start(String[] args) throws Exception {
|
||||
OptionParserCommandLine commandLineArgs = new OptionParserCommandLine();
|
||||
options = commandLineArgs.parse(args);
|
||||
if (options == null) {
|
||||
// Abort
|
||||
return;
|
||||
// A null means end immediately, this may be an error or because
|
||||
// of options like --version. Exit code has been set.
|
||||
return exitCode;
|
||||
}
|
||||
startup = commandLineArgs.startup();
|
||||
// initialize editor settings
|
||||
@ -883,7 +900,7 @@ public class JShellTool implements MessageHandler {
|
||||
// Display just the cause (not a exception backtrace)
|
||||
cmderr.println(ex.getMessage());
|
||||
//abort
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
// Read replay history from last jshell session into previous history
|
||||
replayableHistoryPrevious = ReplayableHistory.fromPrevious(prefs);
|
||||
@ -891,7 +908,7 @@ public class JShellTool implements MessageHandler {
|
||||
for (String loadFile : commandLineArgs.nonOptions()) {
|
||||
if (!runFile(loadFile, "jshell")) {
|
||||
// Load file failed -- abort
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// if we survived that...
|
||||
@ -934,6 +951,7 @@ public class JShellTool implements MessageHandler {
|
||||
}
|
||||
}
|
||||
closeState();
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
private EditorSetting configEditor() {
|
||||
@ -1071,6 +1089,7 @@ public class JShellTool implements MessageHandler {
|
||||
// The feedback mode to use was specified on the command line, use it
|
||||
if (!setFeedback(initmh, new ArgTokenizer("--feedback", initMode))) {
|
||||
regenerateOnDeath = false;
|
||||
exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
String fb = prefs.get(FEEDBACK_KEY);
|
||||
@ -1105,55 +1124,23 @@ public class JShellTool implements MessageHandler {
|
||||
|
||||
/**
|
||||
* Main loop
|
||||
*
|
||||
* @param in the line input/editing context
|
||||
*/
|
||||
private void run(IOContext in) {
|
||||
IOContext oldInput = input;
|
||||
input = in;
|
||||
try {
|
||||
String incomplete = "";
|
||||
// remaining is the source left after one snippet is evaluated
|
||||
String remaining = "";
|
||||
while (live) {
|
||||
String prompt;
|
||||
if (interactive()) {
|
||||
prompt = testPrompt
|
||||
? incomplete.isEmpty()
|
||||
? "\u0005" //ENQ
|
||||
: "\u0006" //ACK
|
||||
: incomplete.isEmpty()
|
||||
? feedback.getPrompt(currentNameSpace.tidNext())
|
||||
: feedback.getContinuationPrompt(currentNameSpace.tidNext())
|
||||
;
|
||||
} else {
|
||||
prompt = "";
|
||||
}
|
||||
String raw;
|
||||
try {
|
||||
raw = in.readLine(prompt, incomplete);
|
||||
} catch (InputInterruptedException ex) {
|
||||
//input interrupted - clearing current state
|
||||
incomplete = "";
|
||||
continue;
|
||||
}
|
||||
if (raw == null) {
|
||||
//EOF
|
||||
if (in.interactiveOutput()) {
|
||||
// End after user ctrl-D
|
||||
regenerateOnDeath = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
String trimmed = trimEnd(raw);
|
||||
if (!trimmed.isEmpty() || !incomplete.isEmpty()) {
|
||||
String line = incomplete + trimmed;
|
||||
|
||||
// No commands in the middle of unprocessed source
|
||||
if (incomplete.isEmpty() && line.startsWith("/") && !line.startsWith("//") && !line.startsWith("/*")) {
|
||||
processCommand(line.trim());
|
||||
} else {
|
||||
incomplete = processSourceCatchingReset(line);
|
||||
}
|
||||
}
|
||||
// Get a line(s) of input
|
||||
String src = getInput(remaining);
|
||||
// Process the snippet or command, returning the remaining source
|
||||
remaining = processInput(src);
|
||||
}
|
||||
} catch (EOFException ex) {
|
||||
// Just exit loop
|
||||
} catch (IOException ex) {
|
||||
errormsg("jshell.err.unexpected.exception", ex);
|
||||
} finally {
|
||||
@ -1161,20 +1148,125 @@ public class JShellTool implements MessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an input command or snippet.
|
||||
*
|
||||
* @param src the source to process
|
||||
* @return any remaining input to processed
|
||||
*/
|
||||
private String processInput(String src) {
|
||||
if (isCommand(src)) {
|
||||
// It is a command
|
||||
processCommand(src.trim());
|
||||
// No remaining input after a command
|
||||
return "";
|
||||
} else {
|
||||
// It is a snipet. Separate the source from the remaining. Evaluate
|
||||
// the source
|
||||
CompletionInfo an = analysis.analyzeCompletion(src);
|
||||
if (processSourceCatchingReset(trimEnd(an.source()))) {
|
||||
// Snippet was successful use any leftover source
|
||||
return an.remaining();
|
||||
} else {
|
||||
// Snippet failed, throw away any remaining source
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input line (or, if incomplete, lines).
|
||||
*
|
||||
* @param initial leading input (left over after last snippet)
|
||||
* @return the complete input snippet or command
|
||||
* @throws IOException on unexpected I/O error
|
||||
*/
|
||||
private String getInput(String initial) throws IOException{
|
||||
String src = initial;
|
||||
while (live) { // loop while incomplete (and live)
|
||||
if (!src.isEmpty()) {
|
||||
// We have some source, see if it is complete, if so, use it
|
||||
String check;
|
||||
|
||||
if (isCommand(src)) {
|
||||
// A command can only be incomplete if it is a /exit with
|
||||
// an argument
|
||||
int sp = src.indexOf(" ");
|
||||
if (sp < 0) return src;
|
||||
check = src.substring(sp).trim();
|
||||
if (check.isEmpty()) return src;
|
||||
String cmd = src.substring(0, sp);
|
||||
Command[] match = findCommand(cmd, c -> c.kind.isRealCommand);
|
||||
if (match.length != 1 || !match[0].command.equals("/exit")) {
|
||||
// A command with no snippet arg, so no multi-line input
|
||||
return src;
|
||||
}
|
||||
} else {
|
||||
// For a snippet check the whole source
|
||||
check = src;
|
||||
}
|
||||
Completeness comp = analysis.analyzeCompletion(check).completeness();
|
||||
if (comp.isComplete() || comp == Completeness.EMPTY) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
String prompt = interactive()
|
||||
? testPrompt
|
||||
? src.isEmpty()
|
||||
? "\u0005" //ENQ -- test prompt
|
||||
: "\u0006" //ACK -- test continuation prompt
|
||||
: src.isEmpty()
|
||||
? feedback.getPrompt(currentNameSpace.tidNext())
|
||||
: feedback.getContinuationPrompt(currentNameSpace.tidNext())
|
||||
: "" // Non-interactive -- no prompt
|
||||
;
|
||||
String line;
|
||||
try {
|
||||
line = input.readLine(prompt, src);
|
||||
} catch (InputInterruptedException ex) {
|
||||
//input interrupted - clearing current state
|
||||
src = "";
|
||||
continue;
|
||||
}
|
||||
if (line == null) {
|
||||
//EOF
|
||||
if (input.interactiveOutput()) {
|
||||
// End after user ctrl-D
|
||||
regenerateOnDeath = false;
|
||||
}
|
||||
throw new EOFException(); // no more input
|
||||
}
|
||||
src = src.isEmpty()
|
||||
? line
|
||||
: src + "\n" + line;
|
||||
}
|
||||
throw new EOFException(); // not longer live
|
||||
}
|
||||
|
||||
private boolean isCommand(String line) {
|
||||
return line.startsWith("/") && !line.startsWith("//") && !line.startsWith("/*");
|
||||
}
|
||||
|
||||
private void addToReplayHistory(String s) {
|
||||
if (!isCurrentlyRunningStartup) {
|
||||
replayableHistory.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
private String processSourceCatchingReset(String src) {
|
||||
/**
|
||||
* Process a source snippet.
|
||||
*
|
||||
* @param src the snippet source to process
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
private boolean processSourceCatchingReset(String src) {
|
||||
try {
|
||||
input.beforeUserCode();
|
||||
return processSource(src);
|
||||
} catch (IllegalStateException ex) {
|
||||
hard("Resetting...");
|
||||
live = false; // Make double sure
|
||||
return "";
|
||||
return false;
|
||||
} finally {
|
||||
input.afterUserCode();
|
||||
}
|
||||
@ -1648,8 +1740,19 @@ public class JShellTool implements MessageHandler {
|
||||
arg -> cmdImports(),
|
||||
EMPTY_COMPLETION_PROVIDER));
|
||||
registerCommand(new Command("/exit",
|
||||
arg -> cmdExit(),
|
||||
EMPTY_COMPLETION_PROVIDER));
|
||||
arg -> cmdExit(arg),
|
||||
(sn, c, a) -> {
|
||||
if (analysis == null || sn.isEmpty()) {
|
||||
// No completions if uninitialized or snippet not started
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
// Give exit code an int context by prefixing the arg
|
||||
List<Suggestion> suggestions = analysis.completionSuggestions(INT_PREFIX + sn,
|
||||
INT_PREFIX.length() + c, a);
|
||||
a[0] -= INT_PREFIX.length();
|
||||
return suggestions;
|
||||
}
|
||||
}));
|
||||
registerCommand(new Command("/env",
|
||||
arg -> cmdEnv(arg),
|
||||
envCompletion()));
|
||||
@ -2128,10 +2231,83 @@ public class JShellTool implements MessageHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean cmdExit() {
|
||||
private boolean cmdExit(String arg) {
|
||||
if (!arg.trim().isEmpty()) {
|
||||
debug("Compiling exit: %s", arg);
|
||||
List<SnippetEvent> events = state.eval(arg);
|
||||
for (SnippetEvent e : events) {
|
||||
// Only care about main snippet
|
||||
if (e.causeSnippet() == null) {
|
||||
Snippet sn = e.snippet();
|
||||
|
||||
// Show any diagnostics
|
||||
List<Diag> diagnostics = state.diagnostics(sn).collect(toList());
|
||||
String source = sn.source();
|
||||
displayDiagnostics(source, diagnostics);
|
||||
|
||||
// Show any exceptions
|
||||
if (e.exception() != null && e.status() != Status.REJECTED) {
|
||||
if (displayException(e.exception())) {
|
||||
// Abort: an exception occurred (reported)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.status() != Status.VALID) {
|
||||
// Abort: can only use valid snippets, diagnostics have been reported (above)
|
||||
return false;
|
||||
}
|
||||
String typeName;
|
||||
if (sn.kind() == Kind.EXPRESSION) {
|
||||
typeName = ((ExpressionSnippet) sn).typeName();
|
||||
} else if (sn.subKind() == TEMP_VAR_EXPRESSION_SUBKIND) {
|
||||
typeName = ((VarSnippet) sn).typeName();
|
||||
} else {
|
||||
// Abort: not an expression
|
||||
errormsg("jshell.err.exit.not.expression", arg);
|
||||
return false;
|
||||
}
|
||||
switch (typeName) {
|
||||
case "int":
|
||||
case "Integer":
|
||||
case "byte":
|
||||
case "Byte":
|
||||
case "short":
|
||||
case "Short":
|
||||
try {
|
||||
int i = Integer.parseInt(e.value());
|
||||
/**
|
||||
addToReplayHistory("/exit " + arg);
|
||||
replayableHistory.storeHistory(prefs);
|
||||
closeState();
|
||||
try {
|
||||
input.close();
|
||||
} catch (Exception exc) {
|
||||
// ignore
|
||||
}
|
||||
* **/
|
||||
exitCode = i;
|
||||
break;
|
||||
} catch (NumberFormatException exc) {
|
||||
// Abort: bad value
|
||||
errormsg("jshell.err.exit.bad.value", arg, e.value());
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
// Abort: bad type
|
||||
errormsg("jshell.err.exit.bad.type", arg, typeName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
regenerateOnDeath = false;
|
||||
live = false;
|
||||
fluffmsg("jshell.msg.goodbye");
|
||||
if (exitCode == 0) {
|
||||
fluffmsg("jshell.msg.goodbye");
|
||||
} else {
|
||||
fluffmsg("jshell.msg.goodbye.value", exitCode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2678,7 +2854,7 @@ public class JShellTool implements MessageHandler {
|
||||
}
|
||||
String tsrc = trimNewlines(an.source());
|
||||
if (!failed && !currSrcs.contains(tsrc)) {
|
||||
failed = processCompleteSource(tsrc);
|
||||
failed = processSource(tsrc);
|
||||
}
|
||||
nextSrcs.add(tsrc);
|
||||
if (an.remaining().isEmpty()) {
|
||||
@ -3118,7 +3294,50 @@ public class JShellTool implements MessageHandler {
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
void displayDiagnostics(String source, Diag diag, List<String> toDisplay) {
|
||||
/**
|
||||
* Print out a snippet exception.
|
||||
*
|
||||
* @param exception the exception to print
|
||||
* @return true on fatal exception
|
||||
*/
|
||||
private boolean displayException(Exception exception) {
|
||||
if (exception instanceof EvalException) {
|
||||
printEvalException((EvalException) exception);
|
||||
return true;
|
||||
} else if (exception instanceof UnresolvedReferenceException) {
|
||||
printUnresolvedException((UnresolvedReferenceException) exception);
|
||||
return false;
|
||||
} else {
|
||||
error("Unexpected execution exception: %s", exception);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a list of diagnostics.
|
||||
*
|
||||
* @param source the source line with the error/warning
|
||||
* @param diagnostics the diagnostics to display
|
||||
*/
|
||||
private void displayDiagnostics(String source, List<Diag> diagnostics) {
|
||||
for (Diag d : diagnostics) {
|
||||
errormsg(d.isError() ? "jshell.msg.error" : "jshell.msg.warning");
|
||||
List<String> disp = new ArrayList<>();
|
||||
displayableDiagnostic(source, d, disp);
|
||||
disp.stream()
|
||||
.forEach(l -> error("%s", l));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a diagnostic into a list of pretty displayable strings with
|
||||
* source context.
|
||||
*
|
||||
* @param source the source line for the error/warning
|
||||
* @param diag the diagnostic to convert
|
||||
* @param toDisplay a list that the displayable strings are added to
|
||||
*/
|
||||
private void displayableDiagnostic(String source, Diag diag, List<String> toDisplay) {
|
||||
for (String line : diag.getMessage(null).split("\\r?\\n")) { // TODO: Internationalize
|
||||
if (!line.trim().startsWith("location:")) {
|
||||
toDisplay.add(line);
|
||||
@ -3169,21 +3388,13 @@ public class JShellTool implements MessageHandler {
|
||||
diag.getStartPosition(), diag.getEndPosition());
|
||||
}
|
||||
|
||||
private String processSource(String srcInput) throws IllegalStateException {
|
||||
while (true) {
|
||||
CompletionInfo an = analysis.analyzeCompletion(srcInput);
|
||||
if (!an.completeness().isComplete()) {
|
||||
return an.remaining();
|
||||
}
|
||||
boolean failed = processCompleteSource(an.source());
|
||||
if (failed || an.remaining().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
srcInput = an.remaining();
|
||||
}
|
||||
}
|
||||
//where
|
||||
boolean processCompleteSource(String source) throws IllegalStateException {
|
||||
/**
|
||||
* Process a source snippet.
|
||||
*
|
||||
* @param source the input source
|
||||
* @return true if the snippet succeeded
|
||||
*/
|
||||
boolean processSource(String source) {
|
||||
debug("Compiling: %s", source);
|
||||
boolean failed = false;
|
||||
boolean isActive = false;
|
||||
@ -3204,7 +3415,7 @@ public class JShellTool implements MessageHandler {
|
||||
addToReplayHistory(source);
|
||||
}
|
||||
|
||||
return failed;
|
||||
return !failed;
|
||||
}
|
||||
|
||||
// Handle incoming snippet events -- return true on failure
|
||||
@ -3218,23 +3429,11 @@ public class JShellTool implements MessageHandler {
|
||||
String source = sn.source();
|
||||
if (ste.causeSnippet() == null) {
|
||||
// main event
|
||||
for (Diag d : diagnostics) {
|
||||
errormsg(d.isError()? "jshell.msg.error" : "jshell.msg.warning");
|
||||
List<String> disp = new ArrayList<>();
|
||||
displayDiagnostics(source, d, disp);
|
||||
disp.stream()
|
||||
.forEach(l -> error("%s", l));
|
||||
}
|
||||
displayDiagnostics(source, diagnostics);
|
||||
|
||||
if (ste.status() != Status.REJECTED) {
|
||||
if (ste.exception() != null) {
|
||||
if (ste.exception() instanceof EvalException) {
|
||||
printEvalException((EvalException) ste.exception());
|
||||
return true;
|
||||
} else if (ste.exception() instanceof UnresolvedReferenceException) {
|
||||
printUnresolvedException((UnresolvedReferenceException) ste.exception());
|
||||
} else {
|
||||
error("Unexpected execution exception: %s", ste.exception());
|
||||
if (displayException(ste.exception())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -3371,7 +3570,7 @@ public class JShellTool implements MessageHandler {
|
||||
this.value = value;
|
||||
this.errorLines = new ArrayList<>();
|
||||
for (Diag d : errors) {
|
||||
displayDiagnostics(sn.source(), d, errorLines);
|
||||
displayableDiagnostic(sn.source(), d, errorLines);
|
||||
}
|
||||
if (resolve) {
|
||||
// resolve needs error lines indented
|
||||
@ -3669,6 +3868,7 @@ class ScannerIOContext extends NonInteractiveIOContext {
|
||||
scannerIn.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUserInput() {
|
||||
return -1;
|
||||
}
|
||||
@ -3700,6 +3900,7 @@ class ReloadIOContext extends NonInteractiveIOContext {
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUserInput() {
|
||||
return -1;
|
||||
}
|
||||
|
@ -229,7 +229,8 @@ public class JShellToolBuilder implements JavaShellToolBuilder {
|
||||
/**
|
||||
* 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
|
||||
* this method may be made from a configured builder.
|
||||
* this method may be made from a configured builder. The exit code from
|
||||
* the Java shell tool is ignored.
|
||||
*
|
||||
* @param arguments the command-line arguments (including options), if any
|
||||
* @throws Exception an unexpected fatal exception
|
||||
@ -239,6 +240,20 @@ public class JShellToolBuilder implements JavaShellToolBuilder {
|
||||
rawTool().start(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* this method may be made from a configured builder.
|
||||
*
|
||||
* @param arguments the command-line arguments (including options), if any
|
||||
* @throws Exception an unexpected fatal exception
|
||||
* @return the exit code
|
||||
*/
|
||||
@Override
|
||||
public int start(String... arguments) throws Exception {
|
||||
return rawTool().start(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistence stored in Preferences.
|
||||
*/
|
||||
|
@ -62,7 +62,8 @@ public class JShellToolProvider implements Tool {
|
||||
* @param err start-up errors and execution "standard" error; use System.err
|
||||
* if null
|
||||
* @param arguments arguments to pass to the tool
|
||||
* @return 0 for success; nonzero otherwise
|
||||
* @return the exit status with which the tool explicitly exited (if any),
|
||||
* otherwise 0 for success or 1 for failure
|
||||
* @throws NullPointerException if the array of arguments contains
|
||||
* any {@code null} elements.
|
||||
*/
|
||||
@ -85,13 +86,12 @@ public class JShellToolProvider implements Tool {
|
||||
? (PrintStream) err
|
||||
: new PrintStream(err);
|
||||
try {
|
||||
JavaShellToolBuilder
|
||||
return JavaShellToolBuilder
|
||||
.builder()
|
||||
.in(xin, null)
|
||||
.out(xout)
|
||||
.err(xerr)
|
||||
.run(arguments);
|
||||
return 0;
|
||||
.start(arguments);
|
||||
} catch (Throwable ex) {
|
||||
xerr.println(ex.getMessage());
|
||||
return 1;
|
||||
@ -109,13 +109,14 @@ public class JShellToolProvider implements Tool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the tool.
|
||||
* Launch the tool and exit.
|
||||
* @param arguments the command-line arguments (including options), if any
|
||||
* @throws Exception an unexpected fatal exception
|
||||
*/
|
||||
public static void main(String[] arguments) throws Exception {
|
||||
JavaShellToolBuilder
|
||||
.builder()
|
||||
.run(arguments);
|
||||
System.exit(
|
||||
JavaShellToolBuilder
|
||||
.builder()
|
||||
.start(arguments));
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,10 @@ jshell.err.no.snippet.with.id = No snippet with id: {0}
|
||||
jshell.err.end.snippet.range.less.than.start = End of snippet range less than start: {0} - {1}
|
||||
jshell.err.range.requires.id = Snippet ranges require snippet ids: {0}
|
||||
|
||||
jshell.err.exit.not.expression = The argument to /exit must be a valid integer expression, it is not an expression: {0}
|
||||
jshell.err.exit.bad.type = The argument to /exit must be a valid integer expression. The type is {1} : {0}
|
||||
jshell.err.exit.bad.value = The argument to /exit has bad value is {1} : {0}
|
||||
|
||||
jshell.err.drop.arg =\
|
||||
In the /drop argument, please specify an import, variable, method, or class to drop.\n\
|
||||
Specify by id or name. Use /list to see ids. Use /reset to reset all state.
|
||||
@ -115,6 +119,7 @@ jshell.err.failed = Failed.
|
||||
jshell.msg.native.method = Native Method
|
||||
jshell.msg.unknown.source = Unknown Source
|
||||
jshell.msg.goodbye = Goodbye
|
||||
jshell.msg.goodbye.value = Goodbye ({0})
|
||||
|
||||
jshell.msg.help.for.help = Type /help for help.
|
||||
|
||||
@ -378,10 +383,17 @@ help.imports =\
|
||||
List the current active jshell imports.
|
||||
|
||||
help.exit.summary = exit jshell
|
||||
help.exit.args =
|
||||
help.exit.args =[<integer-expression-snippet>]
|
||||
help.exit =\
|
||||
Leave the jshell tool. No work is saved.\n\
|
||||
Save any work before using this command
|
||||
Save any work before using this command\n\
|
||||
\n\
|
||||
/exit\n\t\
|
||||
Leave the jshell tool. The exit status is zero.\n\n\
|
||||
/exit <integer-expression-snippet>\n\t\
|
||||
Evaluate the snippet. If the snippet fails or is not an integer expression,\n\t\
|
||||
display the error. Otherwise leave the jshell tool with the\n\t\
|
||||
value of the expression as the exit status
|
||||
|
||||
help.reset.summary = reset jshell
|
||||
help.reset.args = \
|
||||
|
@ -186,10 +186,29 @@ public interface JavaShellToolBuilder {
|
||||
/**
|
||||
* 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
|
||||
* this method may be made from a configured builder.
|
||||
* this method may be made from a configured builder. The exit code from
|
||||
* the Java shell tool is ignored.
|
||||
*
|
||||
* @param arguments the command-line arguments (including options), if any
|
||||
* @throws Exception an unexpected fatal exception
|
||||
*/
|
||||
void run(String... arguments) throws Exception;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* this method may be made from a configured builder.
|
||||
*
|
||||
* @implSpec The default implementation always returns zero. Implementations
|
||||
* of this interface should override this method, returning the exit status.
|
||||
*
|
||||
* @param arguments the command-line arguments (including options), if any
|
||||
* @throws Exception an unexpected fatal exception
|
||||
* @return the exit status with which the tool explicitly exited (if any),
|
||||
* otherwise 0 for success or 1 for failure
|
||||
*/
|
||||
default int start(String... arguments) throws Exception {
|
||||
run(arguments);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -28,23 +28,23 @@
|
||||
* Allows configuration of the tool before launching. A builder is used
|
||||
* to configure and launch the tool.
|
||||
* <p>
|
||||
* At the simplest, a builder is retrieved, and the builder is used to run the
|
||||
* At the simplest, a builder is retrieved, and the builder is used to start the
|
||||
* tool:
|
||||
* <pre>
|
||||
* {@code
|
||||
* JavaShellToolBuilder
|
||||
* .builder()
|
||||
* .run();
|
||||
* .start();
|
||||
* }
|
||||
* </pre>
|
||||
* The builder can be configured and the run can have arguments:
|
||||
* The builder can be configured and the start can have arguments:
|
||||
* <pre>
|
||||
* {@code
|
||||
* JavaShellToolBuilder
|
||||
* .builder()
|
||||
* .out(myCommandPrintStream, myOutputPrintStream)
|
||||
* .locale(Locale.CANADA)
|
||||
* .run("--feedback", "silent", "MyStart");
|
||||
* .start("--feedback", "silent", "MyStart");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
|
@ -21,9 +21,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test 8151754 8080883 8160089 8170162 8166581 8172102 8171343 8178023 8186708 8179856
|
||||
* @summary Testing start-up options.
|
||||
/*
|
||||
* @test 8151754 8080883 8160089 8170162 8166581 8172102 8171343 8178023 8186708 8179856 8185840 8190383
|
||||
* @summary Testing startExCe-up options.
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
@ -32,7 +32,6 @@
|
||||
* @build Compiler toolbox.ToolBox
|
||||
* @run testng StartOptionTest
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
@ -57,239 +56,308 @@ import static org.testng.Assert.fail;
|
||||
@Test
|
||||
public class StartOptionTest {
|
||||
|
||||
private ByteArrayOutputStream cmdout;
|
||||
private ByteArrayOutputStream cmderr;
|
||||
private ByteArrayOutputStream console;
|
||||
private ByteArrayOutputStream userout;
|
||||
private ByteArrayOutputStream usererr;
|
||||
private InputStream cmdInStream;
|
||||
protected ByteArrayOutputStream cmdout;
|
||||
protected ByteArrayOutputStream cmderr;
|
||||
protected ByteArrayOutputStream console;
|
||||
protected ByteArrayOutputStream userout;
|
||||
protected ByteArrayOutputStream usererr;
|
||||
protected InputStream cmdInStream;
|
||||
|
||||
private JavaShellToolBuilder builder() {
|
||||
// turn on logging of launch failures
|
||||
Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL);
|
||||
return JavaShellToolBuilder
|
||||
.builder()
|
||||
.out(new PrintStream(cmdout), new PrintStream(console), new PrintStream(userout))
|
||||
.err(new PrintStream(cmderr), new PrintStream(usererr))
|
||||
.in(cmdInStream, null)
|
||||
.persistence(new HashMap<>())
|
||||
.env(new HashMap<>())
|
||||
.locale(Locale.ROOT);
|
||||
.builder()
|
||||
.out(new PrintStream(cmdout), new PrintStream(console), new PrintStream(userout))
|
||||
.err(new PrintStream(cmderr), new PrintStream(usererr))
|
||||
.in(cmdInStream, null)
|
||||
.persistence(new HashMap<>())
|
||||
.env(new HashMap<>())
|
||||
.locale(Locale.ROOT);
|
||||
}
|
||||
|
||||
private void runShell(String... args) {
|
||||
protected int runShell(String... args) {
|
||||
try {
|
||||
builder()
|
||||
.run(args);
|
||||
return builder()
|
||||
.start(args);
|
||||
} catch (Exception ex) {
|
||||
fail("Repl tool died with exception", ex);
|
||||
}
|
||||
return -1; // for compiler
|
||||
}
|
||||
|
||||
protected void check(ByteArrayOutputStream str, Consumer<String> checkOut, String label) {
|
||||
byte[] bytes = str.toByteArray();
|
||||
str.reset();
|
||||
String out = new String(bytes, StandardCharsets.UTF_8);
|
||||
String out = new String(bytes, StandardCharsets.UTF_8);
|
||||
if (checkOut != null) {
|
||||
checkOut.accept(out);
|
||||
} else {
|
||||
assertEquals("", out, label + ": Expected empty -- ");
|
||||
assertEquals(out, "", label + ": Expected empty -- ");
|
||||
}
|
||||
}
|
||||
|
||||
protected void start(Consumer<String> checkCmdOutput,
|
||||
Consumer<String> checkUserOutput, Consumer<String> checkError,
|
||||
String... args) throws Exception {
|
||||
runShell(args);
|
||||
protected void checkExit(int ec, Consumer<Integer> checkCode) {
|
||||
if (checkCode != null) {
|
||||
checkCode.accept(ec);
|
||||
} else {
|
||||
assertEquals(ec, 0, "Expected standard exit code (0), but found: " + ec);
|
||||
}
|
||||
}
|
||||
|
||||
// Start and check the resultant: exit code (Ex), command output (Co),
|
||||
// user output (Uo), command error (Ce), and console output (Cn)
|
||||
protected void startExCoUoCeCn(Consumer<Integer> checkExitCode,
|
||||
Consumer<String> checkCmdOutput,
|
||||
Consumer<String> checkUserOutput,
|
||||
Consumer<String> checkError,
|
||||
Consumer<String> checkConsole,
|
||||
String... args) {
|
||||
int ec = runShell(args);
|
||||
checkExit(ec, checkExitCode);
|
||||
check(cmdout, checkCmdOutput, "cmdout");
|
||||
check(cmderr, checkError, "cmderr");
|
||||
check(console, null, "console");
|
||||
check(console, checkConsole, "console");
|
||||
check(userout, checkUserOutput, "userout");
|
||||
check(usererr, null, "usererr");
|
||||
}
|
||||
|
||||
protected void start(String expectedCmdOutput, String expectedError, String... args) throws Exception {
|
||||
startWithUserOutput(expectedCmdOutput, "", expectedError, args);
|
||||
// Start with an exit code and command error check
|
||||
protected void startExCe(int eec, Consumer<String> checkError, String... args) {
|
||||
StartOptionTest.this.startExCoUoCeCn(
|
||||
(Integer ec) -> assertEquals((int) ec, eec,
|
||||
"Expected error exit code (" + eec + "), but found: " + ec),
|
||||
null, null, checkError, null, args);
|
||||
}
|
||||
|
||||
private void startWithUserOutput(String expectedCmdOutput, String expectedUserOutput,
|
||||
String expectedError, String... args) throws Exception {
|
||||
start(
|
||||
s -> assertEquals(s.trim(), expectedCmdOutput, "cmdout: "),
|
||||
s -> assertEquals(s.trim(), expectedUserOutput, "userout: "),
|
||||
s -> assertEquals(s.trim(), expectedError, "cmderr: "),
|
||||
// Start with a command output check
|
||||
protected void startCo(Consumer<String> checkCmdOutput, String... args) {
|
||||
StartOptionTest.this.startExCoUoCeCn(null, checkCmdOutput, null, null, null, args);
|
||||
}
|
||||
|
||||
private Consumer<String> assertOrNull(String expected, String label) {
|
||||
return expected == null
|
||||
? null
|
||||
: s -> assertEquals(s.trim(), expected.trim(), label);
|
||||
}
|
||||
|
||||
// Start and check the resultant: exit code (Ex), command output (Co),
|
||||
// user output (Uo), command error (Ce), and console output (Cn)
|
||||
protected void startExCoUoCeCn(int expectedExitCode,
|
||||
String expectedCmdOutput,
|
||||
String expectedUserOutput,
|
||||
String expectedError,
|
||||
String expectedConsole,
|
||||
String... args) {
|
||||
startExCoUoCeCn(
|
||||
expectedExitCode == 0
|
||||
? null
|
||||
: (Integer i) -> assertEquals((int) i, expectedExitCode,
|
||||
"Expected exit code (" + expectedExitCode + "), but found: " + i),
|
||||
assertOrNull(expectedCmdOutput, "cmdout: "),
|
||||
assertOrNull(expectedUserOutput, "userout: "),
|
||||
assertOrNull(expectedError, "cmderr: "),
|
||||
assertOrNull(expectedConsole, "console: "),
|
||||
args);
|
||||
}
|
||||
|
||||
// Start with an expected exit code and command error
|
||||
protected void startExCe(int ec, String expectedError, String... args) {
|
||||
startExCoUoCeCn(ec, null, null, expectedError, null, args);
|
||||
}
|
||||
|
||||
// Start with an expected command output
|
||||
protected void startCo(String expectedCmdOutput, String... args) {
|
||||
startExCoUoCeCn(0, expectedCmdOutput, null, null, null, args);
|
||||
}
|
||||
|
||||
// Start with an expected user output
|
||||
protected void startUo(String expectedUserOutput, String... args) {
|
||||
startExCoUoCeCn(0, null, expectedUserOutput, null, null, args);
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
cmdout = new ByteArrayOutputStream();
|
||||
cmderr = new ByteArrayOutputStream();
|
||||
cmdout = new ByteArrayOutputStream();
|
||||
cmderr = new ByteArrayOutputStream();
|
||||
console = new ByteArrayOutputStream();
|
||||
userout = new ByteArrayOutputStream();
|
||||
usererr = new ByteArrayOutputStream();
|
||||
cmdInStream = new ByteArrayInputStream("/exit\n".getBytes());
|
||||
setIn("/exit\n");
|
||||
}
|
||||
|
||||
protected String writeToFile(String stuff) throws Exception {
|
||||
protected String writeToFile(String stuff) {
|
||||
Compiler compiler = new Compiler();
|
||||
Path p = compiler.getPath("doit.repl");
|
||||
compiler.writeToFile(p, stuff);
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
public void testCommandFile() throws Exception {
|
||||
String fn = writeToFile("String str = \"Hello \"\n/list\nSystem.out.println(str + str)\n/exit\n");
|
||||
startWithUserOutput("1 : String str = \"Hello \";", "Hello Hello", "", "--no-startup", fn, "-s");
|
||||
// Set the input from a String
|
||||
protected void setIn(String s) {
|
||||
cmdInStream = new ByteArrayInputStream(s.getBytes());
|
||||
}
|
||||
|
||||
public void testUsage() throws Exception {
|
||||
// Test load files
|
||||
public void testCommandFile() {
|
||||
String fn = writeToFile("String str = \"Hello \"\n" +
|
||||
"/list\n" +
|
||||
"System.out.println(str + str)\n" +
|
||||
"/exit\n");
|
||||
startExCoUoCeCn(0,
|
||||
"1 : String str = \"Hello \";\n",
|
||||
"Hello Hello",
|
||||
null,
|
||||
null,
|
||||
"--no-startup", fn, "-s");
|
||||
}
|
||||
|
||||
// Test that the usage message is printed
|
||||
public void testUsage() {
|
||||
for (String opt : new String[]{"-h", "--help"}) {
|
||||
start(s -> {
|
||||
startCo(s -> {
|
||||
assertTrue(s.split("\n").length >= 7, "Not enough usage lines: " + s);
|
||||
assertTrue(s.startsWith("Usage: jshell <option>..."), "Unexpect usage start: " + s);
|
||||
assertTrue(s.contains("--show-version"), "Expected help: " + s);
|
||||
assertFalse(s.contains("Welcome"), "Unexpected start: " + s);
|
||||
}, null, null, opt);
|
||||
}, opt);
|
||||
}
|
||||
}
|
||||
|
||||
public void testHelpExtra() throws Exception {
|
||||
// Test the --help-extra message
|
||||
public void testHelpExtra() {
|
||||
for (String opt : new String[]{"-X", "--help-extra"}) {
|
||||
start(s -> {
|
||||
startCo(s -> {
|
||||
assertTrue(s.split("\n").length >= 5, "Not enough help-extra lines: " + s);
|
||||
assertTrue(s.contains("--add-exports"), "Expected --add-exports: " + s);
|
||||
assertTrue(s.contains("--execution"), "Expected --add-exports: " + s);
|
||||
assertFalse(s.contains("Welcome"), "Unexpected start: " + s);
|
||||
}, null, null, opt);
|
||||
}, opt);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnknown() throws Exception {
|
||||
start(null, null,
|
||||
s -> assertEquals(s.trim(), "Unknown option: u"), "-unknown");
|
||||
start(null, null,
|
||||
s -> assertEquals(s.trim(), "Unknown option: unknown"), "--unknown");
|
||||
// Test handling of bogus options
|
||||
public void testUnknown() {
|
||||
startExCe(1, "Unknown option: u", "-unknown");
|
||||
startExCe(1, "Unknown option: unknown", "--unknown");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that input is read with "-" and there is no extra output.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testHypenFile() throws Exception {
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
startWithUserOutput("", "Hello", "", "-");
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
startWithUserOutput("", "Hello", "", "-", "-");
|
||||
Compiler compiler = new Compiler();
|
||||
Path path = compiler.getPath("markload.jsh");
|
||||
compiler.writeToFile(path, "System.out.print(\"===\");");
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
startWithUserOutput("", "===Hello===", "", path.toString(), "-", path.toString());
|
||||
// Test that input is read with "-" and there is no extra output.
|
||||
public void testHypenFile() {
|
||||
setIn("System.out.print(\"Hello\");\n");
|
||||
startUo("Hello", "-");
|
||||
setIn("System.out.print(\"Hello\");\n");
|
||||
startUo("Hello", "-", "-");
|
||||
String fn = writeToFile("System.out.print(\"===\");");
|
||||
setIn("System.out.print(\"Hello\");\n");
|
||||
startUo("===Hello===", fn, "-", fn);
|
||||
// check that errors go to standard error
|
||||
cmdInStream = new ByteArrayInputStream(") Foobar".getBytes());
|
||||
start(
|
||||
s -> assertEquals(s.trim(), "", "cmdout: empty"),
|
||||
s -> assertEquals(s.trim(), "", "userout: empty"),
|
||||
s -> assertTrue(s.contains("illegal start of expression"),
|
||||
"cmderr: illegal start of expression"),
|
||||
setIn(") Foobar");
|
||||
startExCe(0, s -> assertTrue(s.contains("illegal start of expression"),
|
||||
"cmderr: illegal start of expression"),
|
||||
"-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-existent load file sends output to stderr and does not start (no welcome).
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testUnknownLoadFile() throws Exception {
|
||||
start("", "File 'UNKNOWN' for 'jshell' is not found.", "UNKNOWN");
|
||||
// Test that user specified exit codes are propagated
|
||||
public void testExitCode() {
|
||||
setIn("/exit 57\n");
|
||||
startExCoUoCeCn(57, null, null, null, "-> /exit 57", "-s");
|
||||
setIn("int eight = 8\n" +
|
||||
"/exit eight + \n" +
|
||||
" eight\n");
|
||||
startExCoUoCeCn(16, null, null, null,
|
||||
"-> int eight = 8\n" +
|
||||
"-> /exit eight + \n" +
|
||||
">> eight",
|
||||
"-s");
|
||||
}
|
||||
|
||||
public void testStartup() throws Exception {
|
||||
Compiler compiler = new Compiler();
|
||||
Path p = compiler.getPath("file.txt");
|
||||
compiler.writeToFile(p);
|
||||
start("", "Argument to startup missing.", "--startup");
|
||||
start("", "Conflicting options: both --startup and --no-startup were used.", "--no-startup", "--startup", p.toString());
|
||||
start("", "Conflicting options: both --startup and --no-startup were used.", "--startup", p.toString(), "--no-startup");
|
||||
start("", "Argument to startup missing.", "--no-startup", "--startup");
|
||||
// Test that non-existent load file sends output to stderr and does not startExCe (no welcome).
|
||||
public void testUnknownLoadFile() {
|
||||
startExCe(1, "File 'UNKNOWN' for 'jshell' is not found.", "UNKNOWN");
|
||||
}
|
||||
|
||||
public void testStartupFailedOption() throws Exception {
|
||||
start(
|
||||
s -> assertEquals(s.trim(), "", "cmdout: "),
|
||||
s -> assertEquals(s.trim(), "", "userout: "),
|
||||
s -> assertTrue(s.contains("Unrecognized option: -hoge-foo-bar"), "cmderr: " + s),
|
||||
// Test bad usage of the --startup option
|
||||
public void testStartup() {
|
||||
String fn = writeToFile("");
|
||||
startExCe(1, "Argument to startup missing.", "--startup");
|
||||
startExCe(1, "Conflicting options: both --startup and --no-startup were used.", "--no-startup", "--startup", fn);
|
||||
startExCe(1, "Conflicting options: both --startup and --no-startup were used.", "--startup", fn, "--no-startup");
|
||||
startExCe(1, "Argument to startup missing.", "--no-startup", "--startup");
|
||||
}
|
||||
|
||||
// Test an option that causes the back-end to fail is propagated
|
||||
public void testStartupFailedOption() {
|
||||
startExCe(1, s -> assertTrue(s.contains("Unrecognized option: -hoge-foo-bar"), "cmderr: " + s),
|
||||
"-R-hoge-foo-bar");
|
||||
}
|
||||
|
||||
public void testStartupUnknown() throws Exception {
|
||||
start("", "File 'UNKNOWN' for '--startup' is not found.", "--startup", "UNKNOWN");
|
||||
start("", "File 'UNKNOWN' for '--startup' is not found.", "--startup", "DEFAULT", "--startup", "UNKNOWN");
|
||||
// Test the use of non-existant files with the --startup option
|
||||
public void testStartupUnknown() {
|
||||
startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "UNKNOWN");
|
||||
startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "DEFAULT", "--startup", "UNKNOWN");
|
||||
}
|
||||
|
||||
public void testClasspath() throws Exception {
|
||||
for (String cp : new String[] {"--class-path"}) {
|
||||
start("", "Only one --class-path option may be used.", cp, ".", "--class-path", ".");
|
||||
start("", "Argument to class-path missing.", cp);
|
||||
// Test bad usage of --class-path option
|
||||
public void testClasspath() {
|
||||
for (String cp : new String[]{"--class-path"}) {
|
||||
startExCe(1, "Only one --class-path option may be used.", cp, ".", "--class-path", ".");
|
||||
startExCe(1, "Argument to class-path missing.", cp);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnknownModule() throws Exception {
|
||||
start(
|
||||
s -> assertEquals(s.trim(), "", "cmdout: "),
|
||||
s -> assertEquals(s.trim(), "", "userout: "),
|
||||
s -> assertTrue(s.contains("rror") && s.contains("unKnown"), "cmderr: " + s),
|
||||
// Test bogus module on --add-modules option
|
||||
public void testUnknownModule() {
|
||||
startExCe(1, s -> assertTrue(s.contains("rror") && s.contains("unKnown"), "cmderr: " + s),
|
||||
"--add-modules", "unKnown");
|
||||
}
|
||||
|
||||
public void testFeedbackOptionConflict() throws Exception {
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.",
|
||||
// Test that muliple feedback options fail
|
||||
public void testFeedbackOptionConflict() {
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.",
|
||||
"--feedback", "concise", "--feedback", "verbose");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "-s");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "verbose", "-q");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "-v");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-v", "--feedback", "concise");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-q", "-v");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-s", "-v");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-v", "-q");
|
||||
start("", "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-q", "-s");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "-s");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "verbose", "-q");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "-v");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-v", "--feedback", "concise");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-q", "-v");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-s", "-v");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-v", "-q");
|
||||
startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "-q", "-s");
|
||||
}
|
||||
|
||||
public void testNegFeedbackOption() throws Exception {
|
||||
start("", "Argument to feedback missing.", "--feedback");
|
||||
start("", "Does not match any current feedback mode: blorp -- --feedback blorp", "--feedback", "blorp");
|
||||
// Test bogus arguments to the --feedback option
|
||||
public void testNegFeedbackOption() {
|
||||
startExCe(1, "Argument to feedback missing.", "--feedback");
|
||||
startExCe(1, "Does not match any current feedback mode: blorp -- --feedback blorp", "--feedback", "blorp");
|
||||
}
|
||||
|
||||
public void testVersion() throws Exception {
|
||||
start(
|
||||
s -> {
|
||||
assertTrue(s.startsWith("jshell"), "unexpected version: " + s);
|
||||
assertFalse(s.contains("Welcome"), "Unexpected start: " + s);
|
||||
},
|
||||
null, null,
|
||||
// Test --version
|
||||
public void testVersion() {
|
||||
startCo(s -> {
|
||||
assertTrue(s.startsWith("jshell"), "unexpected version: " + s);
|
||||
assertFalse(s.contains("Welcome"), "Unexpected start: " + s);
|
||||
},
|
||||
"--version");
|
||||
}
|
||||
|
||||
public void testShowVersion() throws Exception {
|
||||
runShell("--show-version");
|
||||
check(cmdout,
|
||||
// Test --show-version
|
||||
public void testShowVersion() {
|
||||
startExCoUoCeCn(null,
|
||||
s -> {
|
||||
assertTrue(s.startsWith("jshell"), "unexpected version: " + s);
|
||||
assertTrue(s.contains("Welcome"), "Expected start (but got no welcome): " + s);
|
||||
},
|
||||
"cmdout");
|
||||
check(cmderr, null, "cmderr");
|
||||
check(console,
|
||||
null,
|
||||
null,
|
||||
s -> assertTrue(s.trim().startsWith("jshell>"), "Expected prompt, got: " + s),
|
||||
"console");
|
||||
check(userout, null, "userout");
|
||||
check(usererr, null, "usererr");
|
||||
"--show-version");
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
public void tearDown() {
|
||||
cmdout = null;
|
||||
cmderr = null;
|
||||
cmdout = null;
|
||||
cmderr = null;
|
||||
console = null;
|
||||
userout = null;
|
||||
usererr = null;
|
||||
|
@ -21,21 +21,14 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
import javax.tools.Tool;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8170044 8171343 8179856
|
||||
* @bug 8170044 8171343 8179856 8185840 8190383
|
||||
* @summary Test ServiceLoader launching of jshell tool
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -48,30 +41,25 @@ import static org.testng.Assert.fail;
|
||||
@Test
|
||||
public class ToolProviderTest extends StartOptionTest {
|
||||
|
||||
private ByteArrayOutputStream cmdout;
|
||||
private ByteArrayOutputStream cmderr;
|
||||
private InputStream cmdInStream;
|
||||
|
||||
@BeforeMethod
|
||||
// Through the provider, the console and console go to command out (we assume,
|
||||
// because it works with the current tests) that console and user output are
|
||||
// after command out.
|
||||
@Override
|
||||
public void setUp() {
|
||||
cmdout = new ByteArrayOutputStream();
|
||||
cmderr = new ByteArrayOutputStream();
|
||||
cmdInStream = new ByteArrayInputStream("/exit\n".getBytes());
|
||||
protected void startExCoUoCeCn(int expectedExitCode,
|
||||
String expectedCmdOutput,
|
||||
String expectedUserOutput,
|
||||
String expectedError,
|
||||
String expectedConsole,
|
||||
String... args) {
|
||||
super.startExCoUoCeCn(expectedExitCode,
|
||||
(expectedCmdOutput == null? "" : expectedCmdOutput) +
|
||||
(expectedConsole == null? "" : expectedConsole) +
|
||||
(expectedUserOutput == null? "" : expectedUserOutput),
|
||||
null, expectedError, null, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void start(Consumer<String> checkCmdOutput,
|
||||
Consumer<String> checkUserOutput, Consumer<String> checkError,
|
||||
String... args) throws Exception {
|
||||
if (runShellServiceLoader(args) != 0) {
|
||||
fail("Repl tool failed");
|
||||
}
|
||||
check(cmdout, checkCmdOutput, "cmdout");
|
||||
check(cmderr, checkError, "cmderr");
|
||||
}
|
||||
|
||||
private int runShellServiceLoader(String... args) {
|
||||
protected int runShell(String... args) {
|
||||
ServiceLoader<Tool> sl = ServiceLoader.load(Tool.class);
|
||||
for (Tool provider : sl) {
|
||||
if (provider.name().equals("jshell")) {
|
||||
@ -81,38 +69,14 @@ public class ToolProviderTest extends StartOptionTest {
|
||||
throw new AssertionError("Repl tool not found by ServiceLoader: " + sl);
|
||||
}
|
||||
|
||||
// Test --show-version
|
||||
@Override
|
||||
public void testCommandFile() throws Exception {
|
||||
String fn = writeToFile("String str = \"Hello \"\n/list\nSystem.out.println(str + str)\n/exit\n");
|
||||
start("1 : String str = \"Hello \";" + "\n" + "Hello Hello", "", "--no-startup", fn, "-s");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testShowVersion() throws Exception {
|
||||
start(
|
||||
s -> {
|
||||
assertTrue(s.startsWith("jshell "), "unexpected version: " + s);
|
||||
assertTrue(s.contains("Welcome"), "Expected start (but got no welcome): " + s);
|
||||
assertTrue(s.trim().contains("jshell>"), "Expected prompt, got: " + s);
|
||||
},
|
||||
null, null,
|
||||
public void testShowVersion() {
|
||||
startCo(s -> {
|
||||
assertTrue(s.startsWith("jshell "), "unexpected version: " + s);
|
||||
assertTrue(s.contains("Welcome"), "Expected start (but got no welcome): " + s);
|
||||
assertTrue(s.trim().contains("jshell>"), "Expected prompt, got: " + s);
|
||||
},
|
||||
"--show-version");
|
||||
}
|
||||
/**
|
||||
* Test that input is read with "-" and there is no extra output.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void testHypenFile() throws Exception {
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
start("Hello", "", "-");
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
start("Hello", "", "-", "-");
|
||||
Compiler compiler = new Compiler();
|
||||
Path path = compiler.getPath("markload.jsh");
|
||||
compiler.writeToFile(path, "System.out.print(\"===\");");
|
||||
cmdInStream = new ByteArrayInputStream("System.out.print(\"Hello\");\n".getBytes());
|
||||
start("===Hello===", "", path.toString(), "-", path.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8177076
|
||||
* @bug 8177076 8185840
|
||||
* @modules
|
||||
* jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -107,11 +107,16 @@ public class ToolTabCommandTest extends UITesting {
|
||||
waitOutput(out, Pattern.quote(getResource("help.exit.summary")) + "\n\n" +
|
||||
Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/exit ");
|
||||
inputSink.write("\011");
|
||||
waitOutput(out, Pattern.quote(getResource("help.exit")) + "\n" +
|
||||
waitOutput(out, Pattern.quote(getResource("help.exit").replaceAll("\t", " ")) + "\n" +
|
||||
"\r\u0005/exit ");
|
||||
inputSink.write("\011");
|
||||
waitOutput(out, Pattern.quote(getResource("help.exit.summary")) + "\n\n" +
|
||||
Pattern.quote(getResource("jshell.console.see.full.documentation")) + "\n\r\u0005/exit ");
|
||||
inputSink.write("\u0003");
|
||||
inputSink.write("int zebraStripes = 11\n");
|
||||
waitOutput(out, "zebraStripes ==> 11\n\u0005");
|
||||
inputSink.write("/exit zeb\011");
|
||||
waitOutput(out, "braStr.*es");
|
||||
inputSink.write("\u0003/doesnotexist\011");
|
||||
waitOutput(out, "\u0005/doesnotexist\n" +
|
||||
Pattern.quote(getResource("jshell.console.no.such.command")) + "\n" +
|
||||
|
Loading…
x
Reference in New Issue
Block a user