diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java index c8925a113..fc32733b3 100644 --- a/src/main/java/picocli/CommandLine.java +++ b/src/main/java/picocli/CommandLine.java @@ -12829,13 +12829,19 @@ private int applyValueToSingleValuedField(ArgSpec argSpec, Set initialized, String argDescription) throws Exception { boolean noMoreValues = args.isEmpty(); - String value = args.isEmpty() ? null : args.pop(); + String value = noMoreValues ? null : args.pop(); + String quotedValue = value; if (commandSpec.parser().trimQuotes() && !alreadyUnquoted) {value = unquote(value);} Range arity = argSpec.arity().isUnspecified ? derivedArity : argSpec.arity(); // #509 if (arity.max == 0 && !arity.isUnspecified && lookBehind == LookBehind.ATTACHED_WITH_SEPARATOR) { // #509 throw new MaxValuesExceededException(CommandLine.this, optionDescription("", argSpec, 0) + " should be specified without '" + value + "' parameter"); } + if (arity.min > 0) { + args.push(quotedValue); + assertNoMissingMandatoryParameter(argSpec, args, 0, arity); + args.pop(); + } int consumed = arity.min; // the number or args we need to consume String actualValue = value; diff --git a/src/test/java/picocli/ArityTest.java b/src/test/java/picocli/ArityTest.java index ec75cba68..45eba6c55 100644 --- a/src/test/java/picocli/ArityTest.java +++ b/src/test/java/picocli/ArityTest.java @@ -769,7 +769,7 @@ class App { CommandLine.populateCommand(new App(), "-Long", "-boolean"); fail("should fail"); } catch (CommandLine.ParameterException ex) { - assertEquals("Invalid value for option '-Long': '-boolean' is not a long", ex.getMessage()); + assertEquals("Expected parameter for option '-Long' but found '-boolean'", ex.getMessage()); } } /** see issue #279 */ diff --git a/src/test/java/picocli/CommandLineTest.java b/src/test/java/picocli/CommandLineTest.java index 151a425e8..3a52d45ab 100644 --- a/src/test/java/picocli/CommandLineTest.java +++ b/src/test/java/picocli/CommandLineTest.java @@ -919,16 +919,24 @@ public void testOptionsMixedWithParameters() { } @Test public void testShortOptionsWithSeparatorButNoValueAssignsEmptyStringEvenIfNotLast() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-ro= -v".split(" ")); - verifyCompact(compact, false, true, "-v", null); + try { + CommandLine.populateCommand(new CompactFields(), "-ro= -v".split(" ")); + fail("Expected exception"); + } catch (MissingParameterException ex) { + assertEquals("Expected parameter for option '-o' but found '-v'", ex.getMessage()); + } } @Test public void testShortOptionsWithColonSeparatorButNoValueAssignsEmptyStringEvenIfNotLast() { CompactFields compact = new CompactFields(); CommandLine cmd = new CommandLine(compact); cmd.setSeparator(":"); - cmd.parseArgs("-ro: -v".split(" ")); - verifyCompact(compact, false, true, "-v", null); + try { + cmd.parseArgs("-ro: -v".split(" ")); + fail("Expected exception"); + } catch (MissingParameterException ex) { + assertEquals("Expected parameter for option '-o' but found '-v'", ex.getMessage()); + } } @Test public void testShortOptionsWithSeparatorButNoValueFailsIfValueRequired() { diff --git a/src/test/java/picocli/FallbackTest.java b/src/test/java/picocli/FallbackTest.java index 53d58d05a..7ad217c36 100644 --- a/src/test/java/picocli/FallbackTest.java +++ b/src/test/java/picocli/FallbackTest.java @@ -8,6 +8,7 @@ import org.junit.rules.TestRule; import picocli.CommandLine.Command; import picocli.CommandLine.Option; +import picocli.CommandLine.ParameterException; import picocli.CommandLine.Parameters; import static org.junit.Assert.*; @@ -74,14 +75,24 @@ public void testQuotedSubcommandAssignedToOptionWithFallback() { @Test public void testSubcommandAssignedToOption() { + class MyBadParams implements CommandLine.IParameterExceptionHandler { + ParameterException ex; + public int handleParseException(ParameterException ex, String[] args) throws Exception { + this.ex = ex; + return 2; + } + } + MyBadParams handler = new MyBadParams(); MyCommand cmd = new MyCommand(); int exitCode = new CommandLine(cmd) .setUnmatchedOptionsArePositionalParams(true) + .setParameterExceptionHandler(handler) .execute("-x run app a".split(" ")); - assertEquals("run", cmd.arity1); - assertEquals(0, exitCode); + assertEquals(2, exitCode); + assertEquals(null, cmd.arity1); assertNull(cmd.subApp); - assertArrayEquals(new String[]{"app", "a"}, cmd.params); + assertNotNull(handler.ex); + assertEquals("Expected parameter for option '-x' but found 'run'", handler.ex.getMessage()); } } diff --git a/src/test/java/picocli/LenientParsingTest.java b/src/test/java/picocli/LenientParsingTest.java index 8729eba69..e89949f59 100644 --- a/src/test/java/picocli/LenientParsingTest.java +++ b/src/test/java/picocli/LenientParsingTest.java @@ -190,7 +190,7 @@ class App { cmd.getCommandSpec().parser().collectErrors(true); cmd.parseArgs("-Long", "-boolean"); assertEquals(1, cmd.getParseResult().errors().size()); - assertEquals("Invalid value for option '-Long': '-boolean' is not a long", cmd.getParseResult().errors().get(0).getMessage()); + assertEquals("Expected parameter for option '-Long' but found '-boolean'", cmd.getParseResult().errors().get(0).getMessage()); } @Test public void testBooleanOptionsArity0_nFailsIfAttachedParamNotABoolean() { // ignores varargs diff --git a/src/test/java/picocli/UnmatchedOptionTest.java b/src/test/java/picocli/UnmatchedOptionTest.java index ae3c64706..7a6ecd049 100644 --- a/src/test/java/picocli/UnmatchedOptionTest.java +++ b/src/test/java/picocli/UnmatchedOptionTest.java @@ -115,7 +115,6 @@ class App { assertArrayEquals(new String[]{"4", "5"}, app.y); } - @Ignore @Test public void testSingleValueOptionDoesNotConsumeActualOption() { class App { @@ -123,8 +122,7 @@ class App { @Option(names = "-y") String y; } - //FIXME - expect(new App(), "Missing required parameter for option '-x' ()", MissingParameterException.class, "-y", "-x"); + expect(new App(), "Expected parameter for option '-y' but found '-x'", MissingParameterException.class, "-y", "-x"); } @Test