Skip to content

Commit

Permalink
Add ExpectedAsEnumValues
Browse files Browse the repository at this point in the history
  • Loading branch information
pgolebiowski committed Jul 22, 2023
1 parent b4a1039 commit 80c2f5e
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 6 deletions.
8 changes: 3 additions & 5 deletions src/TreeBasedCli.Tests/CommandArgumentTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Xunit;
using Shouldly;
using System.Threading.Tasks;
using System;

namespace TreeBasedCli.Tests
{
Expand Down Expand Up @@ -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<SampleEnum>();
var command = new SampleCommand(resultHolder);

var commandTree = new CommandTree(root: command);

var handler = new ArgumentHandler(
Expand All @@ -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);
}
}
}
1 change: 1 addition & 0 deletions src/TreeBasedCli.Tests/TreeBasedCli.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
77 changes: 77 additions & 0 deletions src/TreeBasedCli.Tests/UserInputToCommandOptionTests.cs
Original file line number Diff line number Diff line change
@@ -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<TestEnum>();

// 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<TestEnum> result = option.ExpectedAsEnumValues<TestEnum>();

// then
result.ShouldBe(new HashSet<TestEnum> { 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<TestEnum> result = option.ExpectedAsEnumValues<TestEnum>();

// 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<WrongCommandUsageException>(() => option.ExpectedAsEnumValues<TestEnum>());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,14 @@ public interface IUserInputToCommandOption
/// <summary>
/// Gets the single value of this argument, interpreted as a value of the specified enumeration type.
/// This method throws a <see cref="WrongCommandUsageException" /> if the number of values is not equal to 1.
/// It throws a <see cref="MessageOnlyException" /> if the value cannot be mapped to a value of the specified enumeration type.
/// It throws a <see cref="WrongCommandUsageException" /> if the value cannot be mapped to a value of the specified enumeration type.
/// </summary>
TEnum ExpectedAsEnumValue<TEnum>() where TEnum : struct, Enum;

/// <summary>
/// Gets the values of this argument, interpreted as values of the specified enumeration type.
/// It throws a <see cref="WrongCommandUsageException" /> if any of the values cannot be mapped to a value of the specified enumeration type.
/// </summary>
IReadOnlySet<TEnum> ExpectedAsEnumValues<TEnum>() where TEnum : struct, Enum;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,31 @@ public TEnum ExpectedAsEnumValue<TEnum>() where TEnum : struct, Enum
$"Available values are: [ {availableValues} ].");
}
}

/// <inheritdoc cref="IUserInputToCommandOption.ExpectedAsEnumValues{TEnum}" />
public IReadOnlySet<TEnum> ExpectedAsEnumValues<TEnum>() where TEnum : struct, Enum
{
var parsedEnums = new HashSet<TEnum>();

foreach (string value in this.UserInput)
{
try
{
TEnum parsedEnum = Enum.Parse<TEnum>(value);
parsedEnums.Add(parsedEnum);
}
catch
{
string availableValues = string.Join(", ", Enum.GetValues<TEnum>());

throw new WrongCommandUsageException(
this.Command,
$"There is no enum value for {typeof(TEnum)} that maps to '{value}'. " +
$"Available values are: [ {availableValues} ].");
}
}

return parsedEnums;
}
}
}

0 comments on commit 80c2f5e

Please sign in to comment.