diff --git a/spring-shell-core/src/main/java/org/springframework/shell/jline/FileInputProvider.java b/spring-shell-core/src/main/java/org/springframework/shell/jline/FileInputProvider.java index d818137ea..5d9820463 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/jline/FileInputProvider.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/jline/FileInputProvider.java @@ -66,7 +66,13 @@ public Input readInput() { if (line == null) { return null; } else { - ParsedLine parsedLine = parser.parse(sb.toString(), sb.toString().length()); + // gh-277: if it's a commented line then skip as it is equal to NO_INPUT + ParsedLine parsedLine; + if (isCommentedLine(line)) { + parsedLine = parser.parse("", -1, Parser.ParseContext.COMPLETE); + } else { + parsedLine = parser.parse(sb.toString(), sb.toString().length()); + } return new ParsedLineInput(parsedLine); } } @@ -75,4 +81,8 @@ public Input readInput() { public void close() throws IOException { reader.close(); } + + private boolean isCommentedLine(String line) { + return line.matches("\\s*//.*"); + } } diff --git a/spring-shell-core/src/test/java/org/springframework/shell/jline/FileInputProviderTests.java b/spring-shell-core/src/test/java/org/springframework/shell/jline/FileInputProviderTests.java new file mode 100644 index 000000000..2c32e8412 --- /dev/null +++ b/spring-shell-core/src/test/java/org/springframework/shell/jline/FileInputProviderTests.java @@ -0,0 +1,83 @@ +package org.springframework.shell.jline; + +import org.jline.reader.EOFError; +import org.jline.reader.impl.DefaultParser; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.Reader; +import java.io.StringReader; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +class FileInputProviderTests { + private final ExtendedDefaultParser springParser = new ExtendedDefaultParser(); + private final DefaultParser jlineParser = new DefaultParser(); + private FileInputProvider fileInputProvider; + + static Stream regularLinesUnclosedQuotes() { + return Stream.of( + Arguments.of("Regular line with unclosed 'quote"), + Arguments.of("Regular line with unclosed \"quote") + ); + } + + static Stream commentsUnclosedQuotes() { + return Stream.of( + Arguments.of("//Commented line with unclosed 'quote"), + Arguments.of("//Commented line with unclosed \"quote") + ); + } + + @ParameterizedTest + @MethodSource("regularLinesUnclosedQuotes") + void shouldThrowOnUnclosedQuoteDefaultParser(String line) { + jlineParser.setEofOnUnclosedQuote(true); + Reader reader = new StringReader(line); + fileInputProvider = new FileInputProvider(reader, jlineParser); + Exception exception = assertThrows(EOFError.class, () -> { + fileInputProvider.readInput(); + }); + String expectedExceptionMessage = "Missing closing quote"; + String actualExceptionMessage = exception.getMessage(); + assertTrue(actualExceptionMessage.contains(expectedExceptionMessage)); + } + + @ParameterizedTest + @MethodSource("regularLinesUnclosedQuotes") + void shouldThrowOnUnclosedQuoteExtendedParser(String line) { + springParser.setEofOnUnclosedQuote(true); + Reader reader = new StringReader(line); + fileInputProvider = new FileInputProvider(reader, springParser); + Exception exception = assertThrows(EOFError.class, () -> { + fileInputProvider.readInput(); + }); + String expectedExceptionMessage = "Missing closing quote"; + String actualExceptionMessage = exception.getMessage(); + assertTrue(actualExceptionMessage.contains(expectedExceptionMessage)); + } + + @ParameterizedTest + @MethodSource("commentsUnclosedQuotes") + void shoulNotThrowOnUnclosedQuoteDefaultParser(String line) { + jlineParser.setEofOnUnclosedQuote(true); + Reader reader = new StringReader(line); + fileInputProvider = new FileInputProvider(reader, jlineParser); + assertDoesNotThrow(() -> { + fileInputProvider.readInput(); + }); + } + + @ParameterizedTest + @MethodSource("commentsUnclosedQuotes") + void shouldNotThrowOnUnclosedQuoteExtendedParser(String line) { + springParser.setEofOnUnclosedQuote(true); + Reader reader = new StringReader(line); + fileInputProvider = new FileInputProvider(reader, springParser); + assertDoesNotThrow(() -> { + fileInputProvider.readInput(); + }); + } +} \ No newline at end of file