Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ParseResult.ValueForArgument and ValueForOption #949

Merged
merged 7 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions src/System.CommandLine.Tests/ArgumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ public void When_argument_type_is_set_to_null_then_it_throws()
}

[Fact]
public void By_default_the_argument_type_is_void()
public void By_default_the_argument_type_is_string()
{
var argument = new Argument();

argument.ArgumentType
.Should()
.Be(typeof(void));
.Should()
.Be(typeof(string));
}

public class CustomParsing
Expand Down Expand Up @@ -203,8 +203,7 @@ public void custom_parsing_of_scalar_value_from_an_argument_with_one_token()
var argument = new Argument<int>(result => int.Parse(result.Tokens.Single().Value));

argument.Parse("123")
.FindResultFor(argument)
.GetValueOrDefault()
.ValueForArgument(argument)
.Should()
.Be(123);
}
Expand All @@ -215,8 +214,7 @@ public void custom_parsing_of_sequence_value_from_an_argument_with_one_token()
var argument = new Argument<IEnumerable<int>>(result => result.Tokens.Single().Value.Split(',').Select(int.Parse));

argument.Parse("1,2,3")
.FindResultFor(argument)
.GetValueOrDefault()
.ValueForArgument(argument)
.Should()
.BeEquivalentTo(new[] { 1, 2, 3 });
}
Expand All @@ -230,8 +228,7 @@ public void custom_parsing_of_sequence_value_from_an_argument_with_multiple_toke
});

argument.Parse("1 2 3")
.FindResultFor(argument)
.GetValueOrDefault()
.ValueForArgument(argument)
.Should()
.BeEquivalentTo(new[] { 1, 2, 3 });
}
Expand All @@ -245,8 +242,7 @@ public void custom_parsing_of_scalar_value_from_an_argument_with_multiple_tokens
};

argument.Parse("1 2 3")
.FindResultFor(argument)
.GetValueOrDefault()
.ValueForArgument(argument)
.Should()
.Be(6);
}
Expand Down
68 changes: 27 additions & 41 deletions src/System.CommandLine.Tests/Binding/TypeConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,12 @@ public class TypeConversionTests
[Fact]
public void Option_argument_with_arity_of_one_can_be_bound_without_custom_conversion_logic_if_the_type_has_a_constructor_that_takes_a_single_string()
{
var option = new Option("--file")
{
Argument = new Argument<FileInfo>()
};
var option = new Option<FileInfo>("--file");

var file = new FileInfo(Path.Combine(new DirectoryInfo("temp").FullName, "the-file.txt"));
var result = option.Parse($"--file {file.FullName}");

result.ValueForOption("--file")
.Should()
.BeOfType<FileInfo>()
.Which
result.ValueForOption(option)
.Name
.Should()
.Be("the-file.txt");
Expand All @@ -35,19 +29,17 @@ public void Option_argument_with_arity_of_one_can_be_bound_without_custom_conver
[Fact]
public void Command_argument_with_arity_of_one_can_be_bound_without_custom_conversion_logic_if_the_type_has_a_constructor_that_takes_a_single_string()
{
var option = new Command("the-command")
var argument = new Argument<FileInfo>("the-arg");

var command = new Command("the-command")
{
new Argument<FileInfo>("the-arg")
argument
};

var file = new FileInfo(Path.Combine(new DirectoryInfo("temp").FullName, "the-file.txt"));
var result = option.Parse($"{file.FullName}");
var result = command.Parse($"{file.FullName}");

result.CommandResult
.GetArgumentValueOrDefault("the-arg")
.Should()
.BeOfType<FileInfo>()
.Which
result.ValueForArgument(argument)
.Name
.Should()
.Be("the-file.txt");
Expand All @@ -56,38 +48,32 @@ public void Command_argument_with_arity_of_one_can_be_bound_without_custom_conve
[Fact]
public void Command_argument_with_arity_of_zero_or_one_when_type_has_a_constructor_that_takes_a_single_string_returns_null_when_argument_is_not_provided()
{
var argument = new Argument<FileInfo>("the-arg")
{
Arity = ArgumentArity.ZeroOrOne
};
var command = new Command("the-command")
{
new Argument<FileInfo>("the-arg")
{
Arity = ArgumentArity.ZeroOrOne
}
argument
};

var result = command.Parse("");

result.CommandResult
.GetArgumentValueOrDefault("the-arg")
result.ValueForArgument(argument)
.Should()
.BeNull();
}

[Fact]
public void Argument_with_arity_of_many_can_be_called_without_custom_conversion_logic_if_the_item_type_has_a_constructor_that_takes_a_single_string()
{
var option = new Option("--file")
{
Argument = new Argument<FileInfo[]>()
};
var option = new Option<FileInfo[]>("--file");

var file1 = new FileInfo(Path.Combine(new DirectoryInfo("temp").FullName, "file1.txt"));
var file2 = new FileInfo(Path.Combine(new DirectoryInfo("temp").FullName, "file2.txt"));
var result = option.Parse($"--file {file1.FullName} --file {file2.FullName}");

result.ValueForOption("--file")
.Should()
.BeOfType<FileInfo[]>()
.Which
result.ValueForOption(option)
.Select(fi => fi.Name)
.Should()
.BeEquivalentTo("file1.txt", "file2.txt");
Expand Down Expand Up @@ -145,15 +131,13 @@ public void Argument_infers_arity_of_IEnumerable_types_as_OneOrMore(Type type)
[Fact]
public void Argument_bool_will_default_to_true_when_no_argument_is_passed()
{
var parser = new Parser(new Option("-x")
{
Argument = new Argument<bool>()
});
var option = new Option<bool>("-x");
var parser = new Parser(option);

var result = parser.Parse("-x");

result.Errors.Should().BeEmpty();
result.ValueForOption("x").Should().Be(true);
result.ValueForOption(option).Should().Be(true);
}

[Fact]
Expand Down Expand Up @@ -562,17 +546,19 @@ public void A_default_value_with_a_custom_constructor_can_be_specified_for_a_com
[Fact]
public void An_option_argument_with_a_default_argument_can_be_converted_to_the_requested_type()
{
var option = new Option("-x")
{
Argument = new Argument<string>(() => "123")
};

var command = new Command("something")
{
new Option("-x")
{
Argument = new Argument<string>(() => "123")
}
option
};

var result = command.Parse("something");

var value = result.CommandResult.ValueForOption<int>("x");
var value = result.ValueForOption<int>(option);

value.Should().Be(123);
}
Expand Down Expand Up @@ -606,7 +592,7 @@ public void Values_can_be_correctly_converted_to_int_without_the_parser_specifyi
}
};

var value = option.Parse("-x 123").ValueForOption<int>("x");
var value = option.Parse("-x 123").ValueForOption<int>(option);

value.Should().Be(123);
}
Expand Down
14 changes: 0 additions & 14 deletions src/System.CommandLine.Tests/CommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,20 +265,6 @@ public void Subcommands_can_have_aliases()
result.Errors.Should().BeEmpty();
}

[Fact]
public void It_defaults_argument_to_alias_name_when_it_is_not_provided()
{
var command = new Command("-alias")
{
new Argument
{
Arity = ArgumentArity.ZeroOrOne
}
};

command.Arguments.Single().Name.Should().Be("alias");
}

[Fact]
public void It_retains_argument_name_when_it_is_provided()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,18 +303,16 @@ public async Task Method_parameters_of_type_ParseResult_receive_the_current_Bind
{
BindingContext boundContext = default;

var option = new Option<int>("-x");
var command = new Command("command")
{
new Option("-x")
{
Argument = new Argument<int>()
}
option
};
command.Handler = CommandHandler.Create<BindingContext>(context => { boundContext = context; });

await command.InvokeAsync("command -x 123", _console);

boundContext.ParseResult.ValueForOption("-x").Should().Be(123);
boundContext.ParseResult.ValueForOption(option).Should().Be(123);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public async Task Arguments_are_not_suggested()
{
var parser =
new CommandLineBuilder()
.AddArgument(new Argument())
.AddArgument(new Argument("the-argument"))
.AddCommand(new Command("been"))
.UseTypoCorrections()
.Build();
Expand All @@ -117,7 +117,7 @@ public async Task Arguments_are_not_suggested()

await result.InvokeAsync(_console);

_console.Out.ToString().Should().Contain("'een' was not matched. Did you mean 'been'?");
_console.Out.ToString().Should().NotContain("the-argument");
}

[Fact]
Expand Down
28 changes: 28 additions & 0 deletions src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.CommandLine.Parsing;
using System.CommandLine.Tests.Utility;
using FluentAssertions;
using FluentAssertions.Execution;
using Xunit;

namespace System.CommandLine.Tests
Expand Down Expand Up @@ -148,6 +149,33 @@ public void Multiple_arguments_of_unspecified_type_are_parsed_correctly()
.Should()
.Be("dest.txt");
}

[Fact]
public void arity_ambiguities_can_be_differentiated_by_type_convertibility()
{
var ints = new Argument<int[]>();
var strings = new Argument<string[]>();

var root = new RootCommand
{
ints,
strings
};

var result = root.Parse("1 2 3 one", "two");

var _ = new AssertionScope();

result.ValueForArgument(ints)
.Should()
.BeEquivalentTo(new[] { 1, 2, 3 },
options => options.WithStrictOrdering());

result.ValueForArgument(strings)
.Should()
.BeEquivalentTo(new[] { "one", "two" },
options => options.WithStrictOrdering());
}
}
}
}
7 changes: 2 additions & 5 deletions src/System.CommandLine.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1948,14 +1948,11 @@ public void When_option_arguments_are_greater_than_maximum_arity_then_an_error_i
[Fact]
public void Argument_with_custom_type_converter_can_be_bound()
{
var option = new Option("--value")
{
Argument = new Argument<ClassWithCustomTypeConverter>()
};
var option = new Option<ClassWithCustomTypeConverter>("--value");

var parseResult = option.Parse("--value a;b;c");

var instance = (ClassWithCustomTypeConverter)parseResult.ValueForOption("--value");
var instance = parseResult.ValueForOption(option);

instance.Values.Should().BeEquivalentTo("a", "b", "c");
}
Expand Down
5 changes: 2 additions & 3 deletions src/System.CommandLine.Tests/ParsingValidationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.IO;
using FluentAssertions;
using System.Linq;
using System.Reflection;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -281,7 +280,7 @@ public void LegalFilePathsOnly_rejects_command_arguments_containing_invalid_path

result.Errors
.Should()
.Contain(e => e.SymbolResult.Symbol.Name == "the-command" &&
.Contain(e => e.SymbolResult.Symbol == command.Arguments.First() &&
e.Message == $"Character not allowed in a path: {invalidCharacter}");
}

Expand Down Expand Up @@ -429,7 +428,7 @@ public void A_command_argument_can_be_invalid_based_on_file_or_directory_existen
.Should()
.HaveCount(1)
.And
.Contain(e => e.SymbolResult.Symbol.Name == "move" &&
.Contain(e => e.SymbolResult.Symbol == command.Arguments.First() &&
e.Message == $"File or directory does not exist: {path}");
}

Expand Down
Loading