From a413bfa7bacbd7375b5b9b39f1c883e12e50d577 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Thu, 21 Apr 2022 13:06:31 -0700 Subject: [PATCH 1/2] fix #1711 --- .../ParserTests.MultipleArguments.cs | 55 +++++++++++++------ src/System.CommandLine.Tests/ParserTests.cs | 4 +- .../Parsing/ParseResultVisitor.cs | 19 ++++--- .../Parsing/SymbolResultExtensions.cs | 2 +- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs b/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs index 9981788ce9..37cb94b88f 100644 --- a/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs +++ b/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs @@ -2,8 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.CommandLine.Parsing; using System.CommandLine.Tests.Utility; -using System.Threading.Tasks; +using System.Linq; using FluentAssertions; using FluentAssertions.Execution; using Xunit; @@ -149,17 +150,12 @@ public void Multiple_arguments_of_unspecified_type_are_parsed_correctly() public void When_multiple_arguments_are_defined_but_not_provided_then_option_parses_correctly() { var option = new Option("-e"); - var command = new Command("the-command") { option }; - - command.AddArgument(new Argument - { - Name = "arg1", - }); - - command.AddArgument(new Argument + var command = new Command("the-command") { - Name = "arg2", - }); + option, + new Argument(), + new Argument() + }; var result = command.Parse("-e foo"); @@ -168,9 +164,8 @@ public void When_multiple_arguments_are_defined_but_not_provided_then_option_par optionResult.Should().Be("foo"); } - [Fact] - public void tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_next_multiple_arity_argument() + public void Tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_next_multiple_arity_argument() { var ints = new Argument(); var strings = new Argument(); @@ -197,7 +192,7 @@ public void tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_n } [Fact] - public void tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_next_single_arity_argument() + public void Tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_next_single_arity_argument() { var ints = new Argument(); var strings = new Argument(); @@ -232,11 +227,11 @@ public void tokens_that_cannot_be_converted_by_multiple_arity_argument_flow_to_n [Fact] public void Unsatisfied_subsequent_argument_with_min_arity_0_parses_as_default_value() { - var arg1 = new Argument("arg1") + var arg1 = new Argument { Arity = ArgumentArity.ExactlyOne }; - var arg2 = new Argument("arg2") + var arg2 = new Argument { Arity = ArgumentArity.ZeroOrOne, }; @@ -290,6 +285,34 @@ public void When_subsequent_argument_with_ZeroOrOne_arity_is_not_provided_then_p result.GetValueForArgument(argument1).Should().Be("one"); } + + [Theory] // https://github.com/dotnet/command-line-api/issues/1711 + [InlineData("")] + [InlineData("a")] + [InlineData("a b")] + [InlineData("a b c")] + public void When_there_are_not_enough_tokens_for_all_arguments_then_the_correct_number_of_errors_is_reported( + string providedArgs) + { + var command = new Command("command") + { + new Argument(), + new Argument(), + new Argument(), + new Argument() + }; + + var result = new Parser(command).Parse(providedArgs); + + var numberOfMissingArgs = + result + .Errors + .Count(e => e.Message == LocalizationResources.Instance.RequiredArgumentMissing(result.CommandResult)); + + numberOfMissingArgs + .Should() + .Be(4 - providedArgs.Split(" ", StringSplitOptions.RemoveEmptyEntries).Length); + } } } } diff --git a/src/System.CommandLine.Tests/ParserTests.cs b/src/System.CommandLine.Tests/ParserTests.cs index f3ff47ca5a..88c35796b1 100644 --- a/src/System.CommandLine.Tests/ParserTests.cs +++ b/src/System.CommandLine.Tests/ParserTests.cs @@ -16,9 +16,7 @@ namespace System.CommandLine.Tests { public partial class ParserTests - {public partial class RootCommandAndArg0 - { - } + { private readonly ITestOutputHelper _output; public ParserTests(ITestOutputHelper output) diff --git a/src/System.CommandLine/Parsing/ParseResultVisitor.cs b/src/System.CommandLine/Parsing/ParseResultVisitor.cs index b3fe04cbd3..e7c64a5239 100644 --- a/src/System.CommandLine/Parsing/ParseResultVisitor.cs +++ b/src/System.CommandLine/Parsing/ParseResultVisitor.cs @@ -291,21 +291,24 @@ private void ValidateAndConvertArgumentResults(IReadOnlyList arguments _symbolResults.TryAdd(nextArgumentResult.Symbol, nextArgumentResult); } - var argumentResult = _argumentResults[i]; + if (commandArgumentResultCount >= _argumentResults.Count) + { + var argumentResult = _argumentResults[i]; - ValidateAndConvertArgumentResult(argumentResult); + ValidateAndConvertArgumentResult(argumentResult); - if (argumentResult.PassedOnTokens is { } && - i == arguments.Count - 1) - { - _unparsedTokens ??= new List(); - _unparsedTokens.AddRange(argumentResult.PassedOnTokens); + if (argumentResult.PassedOnTokens is { } && + i == arguments.Count - 1) + { + _unparsedTokens ??= new List(); + _unparsedTokens.AddRange(argumentResult.PassedOnTokens); + } } } if (_argumentResults.Count > arguments.Count) { - for (var i = arguments.Count; i < _argumentResults.Count; i++) + for (var i = arguments.Count; i < _argumentResults.Count - 1; i++) { var result = _argumentResults[i]; diff --git a/src/System.CommandLine/Parsing/SymbolResultExtensions.cs b/src/System.CommandLine/Parsing/SymbolResultExtensions.cs index 021f9c56ad..a5e76d7fdf 100644 --- a/src/System.CommandLine/Parsing/SymbolResultExtensions.cs +++ b/src/System.CommandLine/Parsing/SymbolResultExtensions.cs @@ -25,7 +25,7 @@ internal static Token Token(this SymbolResult symbolResult) return symbolResult switch { CommandResult commandResult => commandResult.Token, - OptionResult optionResult => optionResult.Token is null ? CreateImplicitToken(optionResult.Option) : optionResult.Token, + OptionResult optionResult => optionResult.Token ?? CreateImplicitToken(optionResult.Option), _ => throw new ArgumentOutOfRangeException(nameof(symbolResult)) }; From 83ca701f02fd9e0aa309fdb4725870c01ef73f86 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Thu, 21 Apr 2022 13:30:26 -0700 Subject: [PATCH 2/2] fix for net462 build --- src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs b/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs index 37cb94b88f..c84ab54eac 100644 --- a/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs +++ b/src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs @@ -311,7 +311,7 @@ public void When_there_are_not_enough_tokens_for_all_arguments_then_the_correct_ numberOfMissingArgs .Should() - .Be(4 - providedArgs.Split(" ", StringSplitOptions.RemoveEmptyEntries).Length); + .Be(4 - providedArgs.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length); } } }