Skip to content

Commit 4f8bd1e

Browse files
czpilarfmbenhassine
authored andcommitted
Fix boolean flags handling in subcommands
Resolves #1331 Signed-off-by: David Pilar <david@czpilar.net>
1 parent 6f575fc commit 4f8bd1e

2 files changed

Lines changed: 158 additions & 60 deletions

File tree

spring-shell-core/src/main/java/org/springframework/shell/core/command/DefaultCommandParser.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public ParsedInput parse(String input) {
8888
}
8989
List<String> subCommands = firstNonCommandWordIndex == 1 ? Collections.emptyList()
9090
: words.subList(1, firstNonCommandWordIndex);
91+
String fullCommandName = firstNonCommandWordIndex == 1 ? commandName : prefix;
9192

9293
// add command and sub commands
9394
for (String subCommand : subCommands) {
@@ -116,12 +117,12 @@ public ParsedInput parse(String input) {
116117
}
117118
else { // use next word as option value
118119
if (nextWord == null || isOption(nextWord) || isArgumentSeparator(nextWord)) {
119-
if (!isBooleanOption(commandName, currentWord)) {
120+
if (!isBooleanOption(fullCommandName, currentWord)) {
120121
throw new IllegalArgumentException("Option '" + currentWord + "' requires a value");
121122
}
122123
nextWord = "true";
123124
}
124-
else if (isBooleanOption(commandName, currentWord) && !isBooleanValue(nextWord)) {
125+
else if (isBooleanOption(fullCommandName, currentWord) && !isBooleanValue(nextWord)) {
125126
nextWord = "true";
126127
}
127128
else {

spring-shell-core/src/test/java/org/springframework/shell/core/command/DefaultCommandParserTests.java

Lines changed: 155 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -272,62 +272,112 @@ static Stream<Arguments> parseWithQuotedArgumentData() {
272272

273273
@ParameterizedTest
274274
@MethodSource("parseWithBooleanOptionData")
275-
void testParseWithBooleanOption(String input, String longName, char shortName, Class<?> type,
275+
void testParseWithBooleanOption(String input, String commandName, String longName, char shortName, Class<?> type,
276276
String expectedValue) {
277277
// given
278-
Command command = createCommand("mycommand", "My test command");
278+
Command command = createCommand(commandName, "My test command");
279279
command.getOptions().add(CommandOption.with().longName(longName).shortName(shortName).type(type).build());
280280
commandRegistry.registerCommand(command);
281+
281282
// when
282283
ParsedInput parsedInput = parser.parse(input);
284+
String commandWithSubcommands = String
285+
.join(" ", parsedInput.commandName(), String.join(" ", parsedInput.subCommands()))
286+
.trim();
283287

284288
// then
285-
assertEquals("mycommand", parsedInput.commandName());
289+
assertEquals(commandName, commandWithSubcommands);
286290
assertEquals(1, parsedInput.options().size());
287291
assertEquals(longName, parsedInput.options().get(0).longName());
288292
assertEquals(shortName, parsedInput.options().get(0).shortName());
289293
assertEquals(expectedValue, parsedInput.options().get(0).value());
290294
}
291295

292296
static Stream<Arguments> parseWithBooleanOptionData() {
293-
return Stream.of(Arguments.of("mycommand --option=true", "option", ' ', boolean.class, "true"),
294-
Arguments.of("mycommand --option=false", "option", ' ', boolean.class, "false"),
295-
Arguments.of("mycommand --option true", "option", ' ', boolean.class, "true"),
296-
Arguments.of("mycommand --option false", "option", ' ', boolean.class, "false"),
297-
Arguments.of("mycommand --option", "option", ' ', boolean.class, "true"),
298-
299-
Arguments.of("mycommand -on=true", "", 'o', boolean.class, "true"),
300-
Arguments.of("mycommand -o=false", "", 'o', boolean.class, "false"),
301-
Arguments.of("mycommand -o true", "", 'o', boolean.class, "true"),
302-
Arguments.of("mycommand -o false", "", 'o', boolean.class, "false"),
303-
Arguments.of("mycommand -o", "", 'o', boolean.class, "true"),
304-
305-
Arguments.of("mycommand --option=true", "option", ' ', Boolean.class, "true"),
306-
Arguments.of("mycommand --option=false", "option", ' ', Boolean.class, "false"),
307-
Arguments.of("mycommand --option true", "option", ' ', Boolean.class, "true"),
308-
Arguments.of("mycommand --option false", "option", ' ', Boolean.class, "false"),
309-
Arguments.of("mycommand --option", "option", ' ', Boolean.class, "true"),
310-
311-
Arguments.of("mycommand -on=true", "", 'o', Boolean.class, "true"),
312-
Arguments.of("mycommand -o=false", "", 'o', Boolean.class, "false"),
313-
Arguments.of("mycommand -o true", "", 'o', Boolean.class, "true"),
314-
Arguments.of("mycommand -o false", "", 'o', Boolean.class, "false"),
315-
Arguments.of("mycommand -o", "", 'o', Boolean.class, "true"));
297+
return Stream.of(Arguments.of("mycommand --option=true", "mycommand", "option", ' ', boolean.class, "true"),
298+
Arguments.of("mycommand --option=false", "mycommand", "option", ' ', boolean.class, "false"),
299+
Arguments.of("mycommand --option true", "mycommand", "option", ' ', boolean.class, "true"),
300+
Arguments.of("mycommand --option false", "mycommand", "option", ' ', boolean.class, "false"),
301+
Arguments.of("mycommand --option", "mycommand", "option", ' ', boolean.class, "true"),
302+
303+
Arguments.of("mycommand -on=true", "mycommand", "", 'o', boolean.class, "true"),
304+
Arguments.of("mycommand -o=false", "mycommand", "", 'o', boolean.class, "false"),
305+
Arguments.of("mycommand -o true", "mycommand", "", 'o', boolean.class, "true"),
306+
Arguments.of("mycommand -o false", "mycommand", "", 'o', boolean.class, "false"),
307+
Arguments.of("mycommand -o", "mycommand", "", 'o', boolean.class, "true"),
308+
309+
Arguments.of("mycommand --option=true", "mycommand", "option", ' ', Boolean.class, "true"),
310+
Arguments.of("mycommand --option=false", "mycommand", "option", ' ', Boolean.class, "false"),
311+
Arguments.of("mycommand --option true", "mycommand", "option", ' ', Boolean.class, "true"),
312+
Arguments.of("mycommand --option false", "mycommand", "option", ' ', Boolean.class, "false"),
313+
Arguments.of("mycommand --option", "mycommand", "option", ' ', Boolean.class, "true"),
314+
315+
Arguments.of("mycommand -on=true", "mycommand", "", 'o', Boolean.class, "true"),
316+
Arguments.of("mycommand -o=false", "mycommand", "", 'o', Boolean.class, "false"),
317+
Arguments.of("mycommand -o true", "mycommand", "", 'o', Boolean.class, "true"),
318+
Arguments.of("mycommand -o false", "mycommand", "", 'o', Boolean.class, "false"),
319+
Arguments.of("mycommand -o", "mycommand", "", 'o', Boolean.class, "true"),
320+
321+
Arguments.of("thecommand mysubcommand --option=true", "thecommand mysubcommand", "option", ' ',
322+
boolean.class, "true"),
323+
Arguments.of("thecommand mysubcommand --option=false", "thecommand mysubcommand", "option", ' ',
324+
boolean.class, "false"),
325+
Arguments.of("thecommand mysubcommand --option true", "thecommand mysubcommand", "option", ' ',
326+
boolean.class, "true"),
327+
Arguments.of("thecommand mysubcommand --option false", "thecommand mysubcommand", "option", ' ',
328+
boolean.class, "false"),
329+
Arguments.of("thecommand mysubcommand --option", "thecommand mysubcommand", "option", ' ',
330+
boolean.class, "true"),
331+
332+
Arguments.of("thecommand mysubcommand -on=true", "thecommand mysubcommand", "", 'o', boolean.class,
333+
"true"),
334+
Arguments.of("thecommand mysubcommand -o=false", "thecommand mysubcommand", "", 'o', boolean.class,
335+
"false"),
336+
Arguments.of("thecommand mysubcommand -o true", "thecommand mysubcommand", "", 'o', boolean.class,
337+
"true"),
338+
Arguments.of("thecommand mysubcommand -o false", "thecommand mysubcommand", "", 'o', boolean.class,
339+
"false"),
340+
Arguments.of("thecommand mysubcommand -o", "thecommand mysubcommand", "", 'o', boolean.class, "true"),
341+
342+
Arguments.of("thecommand mysubcommand --option=true", "thecommand mysubcommand", "option", ' ',
343+
Boolean.class, "true"),
344+
Arguments.of("thecommand mysubcommand --option=false", "thecommand mysubcommand", "option", ' ',
345+
Boolean.class, "false"),
346+
Arguments.of("thecommand mysubcommand --option true", "thecommand mysubcommand", "option", ' ',
347+
Boolean.class, "true"),
348+
Arguments.of("thecommand mysubcommand --option false", "thecommand mysubcommand", "option", ' ',
349+
Boolean.class, "false"),
350+
Arguments.of("thecommand mysubcommand --option", "thecommand mysubcommand", "option", ' ',
351+
Boolean.class, "true"),
352+
353+
Arguments.of("thecommand mysubcommand -on=true", "thecommand mysubcommand", "", 'o', Boolean.class,
354+
"true"),
355+
Arguments.of("thecommand mysubcommand -o=false", "thecommand mysubcommand", "", 'o', Boolean.class,
356+
"false"),
357+
Arguments.of("thecommand mysubcommand -o true", "thecommand mysubcommand", "", 'o', Boolean.class,
358+
"true"),
359+
Arguments.of("thecommand mysubcommand -o false", "thecommand mysubcommand", "", 'o', Boolean.class,
360+
"false"),
361+
Arguments.of("thecommand mysubcommand -o", "thecommand mysubcommand", "", 'o', Boolean.class, "true"));
316362
}
317363

318364
@ParameterizedTest
319365
@MethodSource("parseWithBooleanOptionAndArgumentData")
320-
void testParseWithBooleanOptionAndArgument(String input, String expectedValue, int expectedArguments,
321-
String expectedArgumentValue) {
366+
void testParseWithBooleanOptionAndArgument(String input, String commandName, String expectedValue,
367+
int expectedArguments, String expectedArgumentValue) {
322368
// given
323-
Command command = createCommand("mycommand", "My test command");
369+
Command command = createCommand(commandName, "My test command");
324370
command.getOptions().add(CommandOption.with().longName("option").type(boolean.class).build());
325371
commandRegistry.registerCommand(command);
372+
326373
// when
327374
ParsedInput parsedInput = parser.parse(input);
375+
String commandWithSubcommands = String
376+
.join(" ", parsedInput.commandName(), String.join(" ", parsedInput.subCommands()))
377+
.trim();
328378

329379
// then
330-
assertEquals("mycommand", parsedInput.commandName());
380+
assertEquals(commandName, commandWithSubcommands);
331381
assertEquals(1, parsedInput.options().size());
332382
assertEquals(expectedValue, parsedInput.options().get(0).value());
333383
assertEquals(expectedArguments, parsedInput.arguments().size());
@@ -337,34 +387,81 @@ void testParseWithBooleanOptionAndArgument(String input, String expectedValue, i
337387
}
338388

339389
static Stream<Arguments> parseWithBooleanOptionAndArgumentData() {
340-
return Stream.of(Arguments.of("mycommand --option=false", "false", 0, null),
341-
Arguments.of("mycommand --option=true", "true", 0, null),
342-
Arguments.of("mycommand --option false", "false", 0, null),
343-
Arguments.of("mycommand --option true", "true", 0, null),
344-
Arguments.of("mycommand --option", "true", 0, null),
345-
346-
Arguments.of("mycommand --option=false argument", "false", 1, "argument"),
347-
Arguments.of("mycommand --option=true argument", "true", 1, "argument"),
348-
Arguments.of("mycommand --option false argument", "false", 1, "argument"),
349-
Arguments.of("mycommand --option true argument", "true", 1, "argument"),
350-
Arguments.of("mycommand --option argument", "true", 1, "argument"),
351-
352-
Arguments.of("mycommand argument --option=false", "false", 1, "argument"),
353-
Arguments.of("mycommand argument --option=true", "true", 1, "argument"),
354-
Arguments.of("mycommand argument --option false", "false", 1, "argument"),
355-
Arguments.of("mycommand argument --option true", "true", 1, "argument"),
356-
Arguments.of("mycommand argument --option", "true", 1, "argument"),
357-
358-
Arguments.of("mycommand --option=false true", "false", 1, "true"),
359-
Arguments.of("mycommand --option=true true", "true", 1, "true"),
360-
Arguments.of("mycommand --option false false", "false", 1, "false"),
361-
Arguments.of("mycommand --option true false", "true", 1, "false"),
362-
363-
Arguments.of("mycommand false --option=false", "false", 1, "false"),
364-
Arguments.of("mycommand false --option=true", "true", 1, "false"),
365-
Arguments.of("mycommand true --option false", "false", 1, "true"),
366-
Arguments.of("mycommand true --option true", "true", 1, "true"),
367-
Arguments.of("mycommand true --option", "true", 1, "true"));
390+
return Stream.of(Arguments.of("mycommand --option=false", "mycommand", "false", 0, null),
391+
Arguments.of("mycommand --option=true", "mycommand", "true", 0, null),
392+
Arguments.of("mycommand --option false", "mycommand", "false", 0, null),
393+
Arguments.of("mycommand --option true", "mycommand", "true", 0, null),
394+
Arguments.of("mycommand --option", "mycommand", "true", 0, null),
395+
396+
Arguments.of("mycommand --option=false argument", "mycommand", "false", 1, "argument"),
397+
Arguments.of("mycommand --option=true argument", "mycommand", "true", 1, "argument"),
398+
Arguments.of("mycommand --option false argument", "mycommand", "false", 1, "argument"),
399+
Arguments.of("mycommand --option true argument", "mycommand", "true", 1, "argument"),
400+
Arguments.of("mycommand --option argument", "mycommand", "true", 1, "argument"),
401+
402+
Arguments.of("mycommand argument --option=false", "mycommand", "false", 1, "argument"),
403+
Arguments.of("mycommand argument --option=true", "mycommand", "true", 1, "argument"),
404+
Arguments.of("mycommand argument --option false", "mycommand", "false", 1, "argument"),
405+
Arguments.of("mycommand argument --option true", "mycommand", "true", 1, "argument"),
406+
Arguments.of("mycommand argument --option", "mycommand", "true", 1, "argument"),
407+
408+
Arguments.of("mycommand --option=false true", "mycommand", "false", 1, "true"),
409+
Arguments.of("mycommand --option=true true", "mycommand", "true", 1, "true"),
410+
Arguments.of("mycommand --option false false", "mycommand", "false", 1, "false"),
411+
Arguments.of("mycommand --option true false", "mycommand", "true", 1, "false"),
412+
413+
Arguments.of("mycommand false --option=false", "mycommand", "false", 1, "false"),
414+
Arguments.of("mycommand false --option=true", "mycommand", "true", 1, "false"),
415+
Arguments.of("mycommand true --option false", "mycommand", "false", 1, "true"),
416+
Arguments.of("mycommand true --option true", "mycommand", "true", 1, "true"),
417+
Arguments.of("mycommand true --option", "mycommand", "true", 1, "true"),
418+
419+
Arguments.of("thecommand mysubcommand --option=false", "thecommand mysubcommand", "false", 0, null),
420+
Arguments.of("thecommand mysubcommand --option=true", "thecommand mysubcommand", "true", 0, null),
421+
Arguments.of("thecommand mysubcommand --option false", "thecommand mysubcommand", "false", 0, null),
422+
Arguments.of("thecommand mysubcommand --option true", "thecommand mysubcommand", "true", 0, null),
423+
Arguments.of("thecommand mysubcommand --option", "thecommand mysubcommand", "true", 0, null),
424+
425+
Arguments.of("thecommand mysubcommand --option=false argument", "thecommand mysubcommand", "false", 1,
426+
"argument"),
427+
Arguments.of("thecommand mysubcommand --option=true argument", "thecommand mysubcommand", "true", 1,
428+
"argument"),
429+
Arguments.of("thecommand mysubcommand --option false argument", "thecommand mysubcommand", "false", 1,
430+
"argument"),
431+
Arguments.of("thecommand mysubcommand --option true argument", "thecommand mysubcommand", "true", 1,
432+
"argument"),
433+
Arguments.of("thecommand mysubcommand --option argument", "thecommand mysubcommand", "true", 1,
434+
"argument"),
435+
436+
Arguments.of("thecommand mysubcommand argument --option=false", "thecommand mysubcommand", "false", 1,
437+
"argument"),
438+
Arguments.of("thecommand mysubcommand argument --option=true", "thecommand mysubcommand", "true", 1,
439+
"argument"),
440+
Arguments.of("thecommand mysubcommand argument --option false", "thecommand mysubcommand", "false", 1,
441+
"argument"),
442+
Arguments.of("thecommand mysubcommand argument --option true", "thecommand mysubcommand", "true", 1,
443+
"argument"),
444+
Arguments.of("thecommand mysubcommand argument --option", "thecommand mysubcommand", "true", 1,
445+
"argument"),
446+
447+
Arguments.of("thecommand mysubcommand --option=false true", "thecommand mysubcommand", "false", 1,
448+
"true"),
449+
Arguments.of("thecommand mysubcommand --option=true true", "thecommand mysubcommand", "true", 1,
450+
"true"),
451+
Arguments.of("thecommand mysubcommand --option false false", "thecommand mysubcommand", "false", 1,
452+
"false"),
453+
Arguments.of("thecommand mysubcommand --option true false", "thecommand mysubcommand", "true", 1,
454+
"false"),
455+
456+
Arguments.of("thecommand mysubcommand false --option=false", "thecommand mysubcommand", "false", 1,
457+
"false"),
458+
Arguments.of("thecommand mysubcommand false --option=true", "thecommand mysubcommand", "true", 1,
459+
"false"),
460+
Arguments.of("thecommand mysubcommand true --option false", "thecommand mysubcommand", "false", 1,
461+
"true"),
462+
Arguments.of("thecommand mysubcommand true --option true", "thecommand mysubcommand", "true", 1,
463+
"true"),
464+
Arguments.of("thecommand mysubcommand true --option", "thecommand mysubcommand", "true", 1, "true"));
368465
}
369466

370467
@ParameterizedTest

0 commit comments

Comments
 (0)