Skip to content

Commit

Permalink
Add ParseResult.ValueForArgument and ValueForOption (#949)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonsequitur authored Jul 2, 2020
1 parent 742b84b commit efc6127
Show file tree
Hide file tree
Showing 22 changed files with 152 additions and 105 deletions.
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

0 comments on commit efc6127

Please sign in to comment.