From 3b9578299be576c758d4cdb02c5266b2ef867bb3 Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Wed, 24 Apr 2024 23:45:13 -0700 Subject: [PATCH 1/2] Fixing issue #2392 There were two problems addressed here. First, the call to Diagram was causing the second error to be added to the ParseResult.Errors collection. The diagram call, was being invoked by the debugger as part of the ParseResult.ToString() method. Causing the number of errors to change when inspecting a parse result. The second issue was the error message text. It was implying that the option expected a single value, when its arity allowed for more. --- .../ParseDiagramTests.cs | 17 +++++++++++++++++ src/System.CommandLine.Tests/ParserTests.cs | 19 +++++++++++++++++-- src/System.CommandLine/ArgumentArity.cs | 19 ++++++++++++++----- .../LocalizationResources.cs | 14 +++++++++++++- .../Parsing/CommandResult.cs | 4 ++-- .../Properties/Resources.Designer.cs | 9 +++++++++ .../Properties/Resources.resx | 3 +++ 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/System.CommandLine.Tests/ParseDiagramTests.cs b/src/System.CommandLine.Tests/ParseDiagramTests.cs index d8ee3621fa..6876a89715 100644 --- a/src/System.CommandLine.Tests/ParseDiagramTests.cs +++ b/src/System.CommandLine.Tests/ParseDiagramTests.cs @@ -47,6 +47,23 @@ public void Parse_result_diagram_displays_unmatched_tokens() .Be("[ command ![ -x ] ]"); } + // https://github.com/dotnet/command-line-api/issues/2392 + [Fact] + public void Parse_diagram_with_option_argument_error_only_one_error_is_returned() + { + var command = new CliCommand("the-command") + { + new CliOption("-x") { Arity = new ArgumentArity(2, 3)} + }; + + ParseResult parseResult = command.Parse("-x 1 -x 2 -x 3 -x 4"); + _ = parseResult.Diagram(); + + parseResult.Errors + .Should() + .ContainSingle(); + } + [Fact] public void Parse_diagram_shows_type_conversion_errors() { diff --git a/src/System.CommandLine.Tests/ParserTests.cs b/src/System.CommandLine.Tests/ParserTests.cs index 5618b41f0f..d484514ea6 100644 --- a/src/System.CommandLine.Tests/ParserTests.cs +++ b/src/System.CommandLine.Tests/ParserTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; @@ -1560,7 +1560,22 @@ public void When_option_arguments_are_greater_than_maximum_arity_then_an_error_i .Should() .Contain(LocalizationResources.UnrecognizedCommandOrArgument("4")); } - + + [Fact] + public void When_the_number_of_option_arguments_are_greater_than_maximum_arity_then_an_error_is_returned() + { + var command = new CliCommand("the-command") + { + new CliOption("-x") { Arity = new ArgumentArity(2, 3)} + }; + + command.Parse("-x 1 -x 2 -x 3 -x 4") + .Errors + .Select(e => e.Message) + .Should() + .Contain(LocalizationResources.OptionArgumentsMaximumExceeded("-x", 3, 4)); + } + [Fact] public void Tokens_are_not_split_if_the_part_before_the_delimiter_is_not_an_option() { diff --git a/src/System.CommandLine/ArgumentArity.cs b/src/System.CommandLine/ArgumentArity.cs index 72acdbdbec..01f06938cd 100644 --- a/src/System.CommandLine/ArgumentArity.cs +++ b/src/System.CommandLine/ArgumentArity.cs @@ -99,11 +99,20 @@ internal static bool Validate(ArgumentResult argumentResult, [NotNullWhen(false) { if (!optionResult.Option.AllowMultipleArgumentsPerToken) { - error = ArgumentConversionResult.Failure( - argumentResult, - LocalizationResources.ExpectsOneArgument(optionResult), - ArgumentConversionResultType.FailedTooManyArguments); - + if (argumentResult.Argument.Arity.MaximumNumberOfValues > 1) + { + error = ArgumentConversionResult.Failure( + argumentResult, + LocalizationResources.OptionArgumentsMaximumExceeded(optionResult, argumentResult.Argument.Arity.MaximumNumberOfValues), + ArgumentConversionResultType.FailedTooManyArguments); + } + else + { + error = ArgumentConversionResult.Failure( + argumentResult, + LocalizationResources.ExpectsOneArgument(optionResult), + ArgumentConversionResultType.FailedTooManyArguments); + } return false; } } diff --git a/src/System.CommandLine/LocalizationResources.cs b/src/System.CommandLine/LocalizationResources.cs index 18f3c33d76..e57dafb9c8 100644 --- a/src/System.CommandLine/LocalizationResources.cs +++ b/src/System.CommandLine/LocalizationResources.cs @@ -14,11 +14,23 @@ namespace System.CommandLine internal static class LocalizationResources { /// - /// Interpolates values into a localized string similar to Command '{0}' expects a single argument but {1} were provided. + /// Interpolates values into a localized string similar to Option '{0}' expects a single argument but {1} were provided. /// internal static string ExpectsOneArgument(OptionResult optionResult) => GetResourceString(Properties.Resources.OptionExpectsOneArgument, GetOptionName(optionResult), optionResult.Tokens.Count); + /// + /// Interpolates values into a localized string similar to Option '{0}' expects at most {1} arguments but {2} were provided. + /// + internal static string OptionArgumentsMaximumExceeded(OptionResult optionResult, int maximumOptionArgumentsAllowed) + => OptionArgumentsMaximumExceeded(GetOptionName(optionResult), maximumOptionArgumentsAllowed, optionResult.Tokens.Count); + + /// + /// Interpolates values into a localized string similar to Option '{0}' expects at most {1} arguments but {2} were provided. + /// + internal static string OptionArgumentsMaximumExceeded(string optionName, int maximumOptionArgumentsAllowed, int foundTokenCount) + => GetResourceString(Properties.Resources.OptionArgumentsMaximumExceeded, optionName, maximumOptionArgumentsAllowed, foundTokenCount); + /// /// Interpolates values into a localized string similar to Directory does not exist: {0}. /// diff --git a/src/System.CommandLine/Parsing/CommandResult.cs b/src/System.CommandLine/Parsing/CommandResult.cs index 9c7c008fa6..07ad4b2624 100644 --- a/src/System.CommandLine/Parsing/CommandResult.cs +++ b/src/System.CommandLine/Parsing/CommandResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; @@ -125,7 +125,7 @@ private void ValidateOptions(bool completeValidation) // When_there_is_an_arity_error_then_further_errors_are_not_reported if (!ArgumentArity.Validate(argumentResult, out var error)) { - optionResult.AddError(error.ErrorMessage!); + argumentResult.AddError(error.ErrorMessage!); continue; } diff --git a/src/System.CommandLine/Properties/Resources.Designer.cs b/src/System.CommandLine/Properties/Resources.Designer.cs index 8d95bb93a4..51bb689206 100644 --- a/src/System.CommandLine/Properties/Resources.Designer.cs +++ b/src/System.CommandLine/Properties/Resources.Designer.cs @@ -294,6 +294,15 @@ internal static string InvalidCharactersInPath { } } + /// + /// Looks up a localized string similar to Option '{0}' expects at most {1} arguments but {2} were provided.. + /// + internal static string OptionArgumentsMaximumExceeded { + get { + return ResourceManager.GetString("OptionArgumentsMaximumExceeded", resourceCulture); + } + } + /// /// Looks up a localized string similar to Option '{0}' expects a single argument but {1} were provided.. /// diff --git a/src/System.CommandLine/Properties/Resources.resx b/src/System.CommandLine/Properties/Resources.resx index 2cd913ede2..1cbd64941d 100644 --- a/src/System.CommandLine/Properties/Resources.resx +++ b/src/System.CommandLine/Properties/Resources.resx @@ -225,4 +225,7 @@ Cannot parse argument '{0}' for option '{1}' as expected type '{2}'. Did you mean one of the following?{3} + + Option '{0}' expects at most {1} arguments but {2} were provided. + \ No newline at end of file From 8c2a744b068475305d364a7015006ff7b98f0113 Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Sat, 27 Apr 2024 11:17:09 -0700 Subject: [PATCH 2/2] Adding additional language files --- src/System.CommandLine/Properties/xlf/Resources.cs.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.de.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.es.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.fr.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.it.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.ja.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.ko.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.pl.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.pt-BR.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.ru.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.tr.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.zh-Hans.xlf | 5 +++++ src/System.CommandLine/Properties/xlf/Resources.zh-Hant.xlf | 5 +++++ 13 files changed, 65 insertions(+) diff --git a/src/System.CommandLine/Properties/xlf/Resources.cs.xlf b/src/System.CommandLine/Properties/xlf/Resources.cs.xlf index d20a81bf04..982e8b7874 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.cs.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.cs.xlf @@ -132,6 +132,11 @@ Znak se v cestě nepovoluje: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.de.xlf b/src/System.CommandLine/Properties/xlf/Resources.de.xlf index 648385ec11..17021f844a 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.de.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.de.xlf @@ -132,6 +132,11 @@ Zeichen in Pfad nicht zulässig: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.es.xlf b/src/System.CommandLine/Properties/xlf/Resources.es.xlf index 3d8efcb17c..cec5015dc5 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.es.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.es.xlf @@ -132,6 +132,11 @@ Carácter no permitido en una ruta: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. La opción '{0}' espera un solo argumento, pero se proporcionaron {1}. diff --git a/src/System.CommandLine/Properties/xlf/Resources.fr.xlf b/src/System.CommandLine/Properties/xlf/Resources.fr.xlf index cee804e763..f723fa6ff8 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.fr.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.fr.xlf @@ -132,6 +132,11 @@ Caractère non autorisé dans un chemin : '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.it.xlf b/src/System.CommandLine/Properties/xlf/Resources.it.xlf index 9801fe92dc..77a9565eaa 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.it.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.it.xlf @@ -132,6 +132,11 @@ Il carattere non è consentito in un percorso: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.ja.xlf b/src/System.CommandLine/Properties/xlf/Resources.ja.xlf index 3370c359b7..47f49b5200 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.ja.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.ja.xlf @@ -132,6 +132,11 @@ パスで使用することが許可されていない文字: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.ko.xlf b/src/System.CommandLine/Properties/xlf/Resources.ko.xlf index e121e576d9..77d57f462b 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.ko.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.ko.xlf @@ -132,6 +132,11 @@ 경로에 사용할 수 없는 문자: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.pl.xlf b/src/System.CommandLine/Properties/xlf/Resources.pl.xlf index 12d431c17e..868f8f2b0b 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.pl.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.pl.xlf @@ -132,6 +132,11 @@ Znak jest niedozwolony w ścieżce: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.pt-BR.xlf b/src/System.CommandLine/Properties/xlf/Resources.pt-BR.xlf index fffee1d8ed..00abc36cf9 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.pt-BR.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.pt-BR.xlf @@ -132,6 +132,11 @@ Caractere não permitido em um caminho: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.ru.xlf b/src/System.CommandLine/Properties/xlf/Resources.ru.xlf index 68a2d6eb24..8da6607efb 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.ru.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.ru.xlf @@ -132,6 +132,11 @@ Недопустимый символ в пути: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.tr.xlf b/src/System.CommandLine/Properties/xlf/Resources.tr.xlf index 5096668256..8d6765432b 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.tr.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.tr.xlf @@ -132,6 +132,11 @@ Yolda '{0}' karakterine izin verilmiyor. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.zh-Hans.xlf b/src/System.CommandLine/Properties/xlf/Resources.zh-Hans.xlf index 507b132746..0f282bc7db 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.zh-Hans.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.zh-Hans.xlf @@ -132,6 +132,11 @@ 路径中不允许的字符: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided. diff --git a/src/System.CommandLine/Properties/xlf/Resources.zh-Hant.xlf b/src/System.CommandLine/Properties/xlf/Resources.zh-Hant.xlf index 72d2f50e2d..befebaf36b 100644 --- a/src/System.CommandLine/Properties/xlf/Resources.zh-Hant.xlf +++ b/src/System.CommandLine/Properties/xlf/Resources.zh-Hant.xlf @@ -132,6 +132,11 @@ 路徑中不允許的字元: '{0}'. + + Option '{0}' expects at most {1} arguments but {2} were provided. + Option '{0}' expects at most {1} arguments but {2} were provided. + + Option '{0}' expects a single argument but {1} were provided. Option '{0}' expects a single argument but {1} were provided.