Fix inconsistent unknown option parsing
- Fix an issue where unknown option is wrongly lexed as an argument if it's later than an known valid option. - Essentially if `arg1` is only valid option `--arg1 value1 --arg2 value2` would not complain about `arg2`. - Backport #1120 - Fixes #1123
This commit is contained in:
@@ -222,7 +222,13 @@ public interface Lexer {
|
||||
}
|
||||
}
|
||||
else if (isLastTokenOfType(tokenList, TokenType.ARGUMENT)) {
|
||||
tokenList.add(Token.of(argument, TokenType.ARGUMENT, i2));
|
||||
int decuceArgumentStyle = decuceArgumentStyle(argument);
|
||||
if (decuceArgumentStyle < 0) {
|
||||
tokenList.add(Token.of(argument, TokenType.ARGUMENT, i2));
|
||||
}
|
||||
else {
|
||||
tokenList.add(Token.of(argument, TokenType.OPTION, i2));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -416,4 +416,11 @@ abstract class AbstractParsingTests {
|
||||
Parser parser = new Parser.DefaultParser(commandModel, lexer(config), ast, config);
|
||||
return parser.parse(Arrays.asList(arguments));
|
||||
}
|
||||
|
||||
record RegAndArgs(CommandRegistration reg, String... args) {
|
||||
static RegAndArgs of(CommandRegistration reg, String... args) {
|
||||
return new RegAndArgs(reg, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -274,6 +274,38 @@ class LexerTests extends AbstractParsingTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void notDefinedOptionShouldBeOptionAfterDefinedOptionHavingArgument() {
|
||||
register(ROOT3);
|
||||
List<Token> tokens = tokenize("root3", "--arg1", "value1", "--arg2");
|
||||
|
||||
assertThat(tokens).satisfiesExactly(
|
||||
token -> {
|
||||
ParserAssertions.assertThat(token)
|
||||
.isType(TokenType.COMMAND)
|
||||
.hasPosition(0)
|
||||
.hasValue("root3");
|
||||
},
|
||||
token -> {
|
||||
ParserAssertions.assertThat(token)
|
||||
.isType(TokenType.OPTION)
|
||||
.hasPosition(1)
|
||||
.hasValue("--arg1");
|
||||
},
|
||||
token -> {
|
||||
ParserAssertions.assertThat(token)
|
||||
.isType(TokenType.ARGUMENT)
|
||||
.hasPosition(2)
|
||||
.hasValue("value1");
|
||||
},
|
||||
token -> {
|
||||
ParserAssertions.assertThat(token)
|
||||
.isType(TokenType.OPTION)
|
||||
.hasPosition(3)
|
||||
.hasValue("--arg2");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void optionsWithoutValuesFromRoot() {
|
||||
register(ROOT5);
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
*/
|
||||
package org.springframework.shell.command.parser;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import org.springframework.shell.command.parser.Parser.ParseResult;
|
||||
import org.springframework.shell.command.parser.ParserConfig.Feature;
|
||||
@@ -161,6 +165,31 @@ class ParserTests extends AbstractParsingTests {
|
||||
);
|
||||
}
|
||||
|
||||
static Stream<RegAndArgs> shouldHaveErrorForUnrecognisedOption() {
|
||||
return Stream.of(
|
||||
RegAndArgs.of(ROOT1, "root1", "--arg1"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg2", "--arg1"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg1", "--arg2"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg2", "fake1", "--arg1"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg1", "--arg2", "fake1"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg2", "fake1", "--arg1", "fake2"),
|
||||
RegAndArgs.of(ROOT3, "root3", "--arg1", "fake2", "--arg2", "fake1")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void shouldHaveErrorForUnrecognisedOption(RegAndArgs regAndArgs) {
|
||||
register(regAndArgs.reg());
|
||||
ParseResult result = parse(regAndArgs.args());
|
||||
assertThat(result.messageResults()).satisfiesExactlyInAnyOrder(
|
||||
message -> {
|
||||
ParserAssertions.assertThat(message.parserMessage()).hasCode(2001).hasType(ParserMessage.Type.ERROR);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void lexerMessageShouldGetPropagated() {
|
||||
ParseResult parse = parse("--");
|
||||
|
||||
Reference in New Issue
Block a user