From 80c2f5e76fad777d6fa4712dcfe9056f05d9f9a4 Mon Sep 17 00:00:00 2001 From: Patryk Golebiowski Date: Sat, 22 Jul 2023 13:44:45 +0200 Subject: [PATCH] Add `ExpectedAsEnumValues` --- .../CommandArgumentTests.cs | 8 +- .../TreeBasedCli.Tests.csproj | 1 + .../UserInputToCommandOptionTests.cs | 77 +++++++++++++++++++ .../IUserInputToCommandOption.cs | 8 +- .../WithArguments/UserInputToCommandOption.cs | 26 +++++++ 5 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/TreeBasedCli.Tests/UserInputToCommandOptionTests.cs diff --git a/src/TreeBasedCli.Tests/CommandArgumentTests.cs b/src/TreeBasedCli.Tests/CommandArgumentTests.cs index f47f1a6..f420c2a 100644 --- a/src/TreeBasedCli.Tests/CommandArgumentTests.cs +++ b/src/TreeBasedCli.Tests/CommandArgumentTests.cs @@ -1,6 +1,6 @@ using Xunit; +using Shouldly; using System.Threading.Tasks; -using System; namespace TreeBasedCli.Tests { @@ -39,12 +39,11 @@ public override Task TaskToRun(CommandArguments commandArguments) } [Fact] - public async Task should_parse_correct_enum_value() + public async Task GivenEnumArgument_CorrectValueIsAssignedToCommandHandler() { // given var resultHolder = new FutureValueHolder(); var command = new SampleCommand(resultHolder); - var commandTree = new CommandTree(root: command); var handler = new ArgumentHandler( @@ -54,8 +53,7 @@ public async Task should_parse_correct_enum_value() await handler.HandleAsync(new[] { "--enum-value", "Two" }); // then - Console.WriteLine($"received value: {resultHolder.Value}"); - Assert.Equal(SampleEnum.Two, resultHolder.Value); + resultHolder.Value.ShouldBe(SampleEnum.Two); } } } diff --git a/src/TreeBasedCli.Tests/TreeBasedCli.Tests.csproj b/src/TreeBasedCli.Tests/TreeBasedCli.Tests.csproj index 5342734..e7c3922 100644 --- a/src/TreeBasedCli.Tests/TreeBasedCli.Tests.csproj +++ b/src/TreeBasedCli.Tests/TreeBasedCli.Tests.csproj @@ -8,6 +8,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/TreeBasedCli.Tests/UserInputToCommandOptionTests.cs b/src/TreeBasedCli.Tests/UserInputToCommandOptionTests.cs new file mode 100644 index 0000000..94f0bda --- /dev/null +++ b/src/TreeBasedCli.Tests/UserInputToCommandOptionTests.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using Shouldly; +using TreeBasedCli.Exceptions; +using Xunit; + +namespace TreeBasedCli.Tests +{ + public class UserInputToCommandOptionTests + { + public enum TestEnum + { + Value1, + Value2, + Value3 + } + + [Theory] + [InlineData("Value1", TestEnum.Value1)] + [InlineData("Value2", TestEnum.Value2)] + [InlineData("Value3", TestEnum.Value3)] + public void ExpectedAsEnumValue_ShouldReturnCorrectEnumValue(string input, TestEnum expected) + { + // given + var command = new Command("test-command", new[] { "Test Description" }); + var userInput = new[] { input }; + var option = new UserInputToCommandOption(command, "--test-option", userInput); + + // when + TestEnum result = option.ExpectedAsEnumValue(); + + // then + result.ShouldBe(expected); + } + + [Fact] + public void ExpectedAsEnumValues_ShouldReturnCorrectEnumValues() + { + // given + var command = new Command("test-command", new[] { "Test Description" }); + var userInput = new[] { "Value1", "Value2", "Value3" }; + var option = new UserInputToCommandOption(command, "--test-option", userInput); + + // whtn + IReadOnlySet result = option.ExpectedAsEnumValues(); + + // then + result.ShouldBe(new HashSet { TestEnum.Value1, TestEnum.Value2, TestEnum.Value3 }, ignoreOrder: true); + } + + [Fact] + public void ExpectedAsEnumValues_WhenInputIsEmpty_ShouldReturnEmptySet() + { + // given + var command = new Command("test-command", new[] { "Test Description" }); + var userInput = new string[] { }; + var option = new UserInputToCommandOption(command, "--test-option", userInput); + + // when + IReadOnlySet result = option.ExpectedAsEnumValues(); + + // then + result.ShouldBeEmpty(); + } + + [Fact] + public void ExpectedAsEnumValues_WhenInvalidEnumValueProvided_ShouldThrowMessageOnlyException() + { + // given + var command = new Command("test-command", new[] { "Test Description" }); + var userInput = new[] { "InvalidValue" }; + var option = new UserInputToCommandOption(command, "--test-option", userInput); + + // when + Should.Throw(() => option.ExpectedAsEnumValues()); + } + } +} diff --git a/src/TreeBasedCli/Commands/Leaf/WithArguments/IUserInputToCommandOption.cs b/src/TreeBasedCli/Commands/Leaf/WithArguments/IUserInputToCommandOption.cs index 70a682c..f9f0f10 100644 --- a/src/TreeBasedCli/Commands/Leaf/WithArguments/IUserInputToCommandOption.cs +++ b/src/TreeBasedCli/Commands/Leaf/WithArguments/IUserInputToCommandOption.cs @@ -58,8 +58,14 @@ public interface IUserInputToCommandOption /// /// Gets the single value of this argument, interpreted as a value of the specified enumeration type. /// This method throws a if the number of values is not equal to 1. - /// It throws a if the value cannot be mapped to a value of the specified enumeration type. + /// It throws a if the value cannot be mapped to a value of the specified enumeration type. /// TEnum ExpectedAsEnumValue() where TEnum : struct, Enum; + + /// + /// Gets the values of this argument, interpreted as values of the specified enumeration type. + /// It throws a if any of the values cannot be mapped to a value of the specified enumeration type. + /// + IReadOnlySet ExpectedAsEnumValues() where TEnum : struct, Enum; } } diff --git a/src/TreeBasedCli/Commands/Leaf/WithArguments/UserInputToCommandOption.cs b/src/TreeBasedCli/Commands/Leaf/WithArguments/UserInputToCommandOption.cs index c2e834a..061aaf6 100644 --- a/src/TreeBasedCli/Commands/Leaf/WithArguments/UserInputToCommandOption.cs +++ b/src/TreeBasedCli/Commands/Leaf/WithArguments/UserInputToCommandOption.cs @@ -109,5 +109,31 @@ public TEnum ExpectedAsEnumValue() where TEnum : struct, Enum $"Available values are: [ {availableValues} ]."); } } + + /// + public IReadOnlySet ExpectedAsEnumValues() where TEnum : struct, Enum + { + var parsedEnums = new HashSet(); + + foreach (string value in this.UserInput) + { + try + { + TEnum parsedEnum = Enum.Parse(value); + parsedEnums.Add(parsedEnum); + } + catch + { + string availableValues = string.Join(", ", Enum.GetValues()); + + throw new WrongCommandUsageException( + this.Command, + $"There is no enum value for {typeof(TEnum)} that maps to '{value}'. " + + $"Available values are: [ {availableValues} ]."); + } + } + + return parsedEnums; + } } }