Skip to content

Commit efc6127

Browse files
authored
Add ParseResult.ValueForArgument and ValueForOption (#949)
1 parent 742b84b commit efc6127

22 files changed

+152
-105
lines changed

src/System.CommandLine.Tests/ArgumentTests.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ public void When_argument_type_is_set_to_null_then_it_throws()
6767
}
6868

6969
[Fact]
70-
public void By_default_the_argument_type_is_void()
70+
public void By_default_the_argument_type_is_string()
7171
{
7272
var argument = new Argument();
7373

7474
argument.ArgumentType
75-
.Should()
76-
.Be(typeof(void));
75+
.Should()
76+
.Be(typeof(string));
7777
}
7878

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

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

217216
argument.Parse("1,2,3")
218-
.FindResultFor(argument)
219-
.GetValueOrDefault()
217+
.ValueForArgument(argument)
220218
.Should()
221219
.BeEquivalentTo(new[] { 1, 2, 3 });
222220
}
@@ -230,8 +228,7 @@ public void custom_parsing_of_sequence_value_from_an_argument_with_multiple_toke
230228
});
231229

232230
argument.Parse("1 2 3")
233-
.FindResultFor(argument)
234-
.GetValueOrDefault()
231+
.ValueForArgument(argument)
235232
.Should()
236233
.BeEquivalentTo(new[] { 1, 2, 3 });
237234
}
@@ -245,8 +242,7 @@ public void custom_parsing_of_scalar_value_from_an_argument_with_multiple_tokens
245242
};
246243

247244
argument.Parse("1 2 3")
248-
.FindResultFor(argument)
249-
.GetValueOrDefault()
245+
.ValueForArgument(argument)
250246
.Should()
251247
.Be(6);
252248
}

src/System.CommandLine.Tests/Binding/TypeConversionTests.cs

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,12 @@ public class TypeConversionTests
1515
[Fact]
1616
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()
1717
{
18-
var option = new Option("--file")
19-
{
20-
Argument = new Argument<FileInfo>()
21-
};
18+
var option = new Option<FileInfo>("--file");
2219

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

26-
result.ValueForOption("--file")
27-
.Should()
28-
.BeOfType<FileInfo>()
29-
.Which
23+
result.ValueForOption(option)
3024
.Name
3125
.Should()
3226
.Be("the-file.txt");
@@ -35,19 +29,17 @@ public void Option_argument_with_arity_of_one_can_be_bound_without_custom_conver
3529
[Fact]
3630
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()
3731
{
38-
var option = new Command("the-command")
32+
var argument = new Argument<FileInfo>("the-arg");
33+
34+
var command = new Command("the-command")
3935
{
40-
new Argument<FileInfo>("the-arg")
36+
argument
4137
};
4238

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

46-
result.CommandResult
47-
.GetArgumentValueOrDefault("the-arg")
48-
.Should()
49-
.BeOfType<FileInfo>()
50-
.Which
42+
result.ValueForArgument(argument)
5143
.Name
5244
.Should()
5345
.Be("the-file.txt");
@@ -56,38 +48,32 @@ public void Command_argument_with_arity_of_one_can_be_bound_without_custom_conve
5648
[Fact]
5749
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()
5850
{
51+
var argument = new Argument<FileInfo>("the-arg")
52+
{
53+
Arity = ArgumentArity.ZeroOrOne
54+
};
5955
var command = new Command("the-command")
6056
{
61-
new Argument<FileInfo>("the-arg")
62-
{
63-
Arity = ArgumentArity.ZeroOrOne
64-
}
57+
argument
6558
};
6659

6760
var result = command.Parse("");
6861

69-
result.CommandResult
70-
.GetArgumentValueOrDefault("the-arg")
62+
result.ValueForArgument(argument)
7163
.Should()
7264
.BeNull();
7365
}
7466

7567
[Fact]
7668
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()
7769
{
78-
var option = new Option("--file")
79-
{
80-
Argument = new Argument<FileInfo[]>()
81-
};
70+
var option = new Option<FileInfo[]>("--file");
8271

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

87-
result.ValueForOption("--file")
88-
.Should()
89-
.BeOfType<FileInfo[]>()
90-
.Which
76+
result.ValueForOption(option)
9177
.Select(fi => fi.Name)
9278
.Should()
9379
.BeEquivalentTo("file1.txt", "file2.txt");
@@ -145,15 +131,13 @@ public void Argument_infers_arity_of_IEnumerable_types_as_OneOrMore(Type type)
145131
[Fact]
146132
public void Argument_bool_will_default_to_true_when_no_argument_is_passed()
147133
{
148-
var parser = new Parser(new Option("-x")
149-
{
150-
Argument = new Argument<bool>()
151-
});
134+
var option = new Option<bool>("-x");
135+
var parser = new Parser(option);
152136

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

155139
result.Errors.Should().BeEmpty();
156-
result.ValueForOption("x").Should().Be(true);
140+
result.ValueForOption(option).Should().Be(true);
157141
}
158142

159143
[Fact]
@@ -562,17 +546,19 @@ public void A_default_value_with_a_custom_constructor_can_be_specified_for_a_com
562546
[Fact]
563547
public void An_option_argument_with_a_default_argument_can_be_converted_to_the_requested_type()
564548
{
549+
var option = new Option("-x")
550+
{
551+
Argument = new Argument<string>(() => "123")
552+
};
553+
565554
var command = new Command("something")
566555
{
567-
new Option("-x")
568-
{
569-
Argument = new Argument<string>(() => "123")
570-
}
556+
option
571557
};
572558

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

575-
var value = result.CommandResult.ValueForOption<int>("x");
561+
var value = result.ValueForOption<int>(option);
576562

577563
value.Should().Be(123);
578564
}
@@ -606,7 +592,7 @@ public void Values_can_be_correctly_converted_to_int_without_the_parser_specifyi
606592
}
607593
};
608594

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

611597
value.Should().Be(123);
612598
}

src/System.CommandLine.Tests/CommandTests.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -265,20 +265,6 @@ public void Subcommands_can_have_aliases()
265265
result.Errors.Should().BeEmpty();
266266
}
267267

268-
[Fact]
269-
public void It_defaults_argument_to_alias_name_when_it_is_not_provided()
270-
{
271-
var command = new Command("-alias")
272-
{
273-
new Argument
274-
{
275-
Arity = ArgumentArity.ZeroOrOne
276-
}
277-
};
278-
279-
command.Arguments.Single().Name.Should().Be("alias");
280-
}
281-
282268
[Fact]
283269
public void It_retains_argument_name_when_it_is_provided()
284270
{

src/System.CommandLine.Tests/Invocation/CommandHandlerTests.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,18 +303,16 @@ public async Task Method_parameters_of_type_ParseResult_receive_the_current_Bind
303303
{
304304
BindingContext boundContext = default;
305305

306+
var option = new Option<int>("-x");
306307
var command = new Command("command")
307308
{
308-
new Option("-x")
309-
{
310-
Argument = new Argument<int>()
311-
}
309+
option
312310
};
313311
command.Handler = CommandHandler.Create<BindingContext>(context => { boundContext = context; });
314312

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

317-
boundContext.ParseResult.ValueForOption("-x").Should().Be(123);
315+
boundContext.ParseResult.ValueForOption(option).Should().Be(123);
318316
}
319317

320318
[Fact]

src/System.CommandLine.Tests/Invocation/TypoCorrectionTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public async Task Arguments_are_not_suggested()
108108
{
109109
var parser =
110110
new CommandLineBuilder()
111-
.AddArgument(new Argument())
111+
.AddArgument(new Argument("the-argument"))
112112
.AddCommand(new Command("been"))
113113
.UseTypoCorrections()
114114
.Build();
@@ -117,7 +117,7 @@ public async Task Arguments_are_not_suggested()
117117

118118
await result.InvokeAsync(_console);
119119

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

123123
[Fact]

src/System.CommandLine.Tests/ParserTests.MultipleArguments.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.CommandLine.Parsing;
66
using System.CommandLine.Tests.Utility;
77
using FluentAssertions;
8+
using FluentAssertions.Execution;
89
using Xunit;
910

1011
namespace System.CommandLine.Tests
@@ -148,6 +149,33 @@ public void Multiple_arguments_of_unspecified_type_are_parsed_correctly()
148149
.Should()
149150
.Be("dest.txt");
150151
}
152+
153+
[Fact]
154+
public void arity_ambiguities_can_be_differentiated_by_type_convertibility()
155+
{
156+
var ints = new Argument<int[]>();
157+
var strings = new Argument<string[]>();
158+
159+
var root = new RootCommand
160+
{
161+
ints,
162+
strings
163+
};
164+
165+
var result = root.Parse("1 2 3 one", "two");
166+
167+
var _ = new AssertionScope();
168+
169+
result.ValueForArgument(ints)
170+
.Should()
171+
.BeEquivalentTo(new[] { 1, 2, 3 },
172+
options => options.WithStrictOrdering());
173+
174+
result.ValueForArgument(strings)
175+
.Should()
176+
.BeEquivalentTo(new[] { "one", "two" },
177+
options => options.WithStrictOrdering());
178+
}
151179
}
152180
}
153181
}

src/System.CommandLine.Tests/ParserTests.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,14 +1948,11 @@ public void When_option_arguments_are_greater_than_maximum_arity_then_an_error_i
19481948
[Fact]
19491949
public void Argument_with_custom_type_converter_can_be_bound()
19501950
{
1951-
var option = new Option("--value")
1952-
{
1953-
Argument = new Argument<ClassWithCustomTypeConverter>()
1954-
};
1951+
var option = new Option<ClassWithCustomTypeConverter>("--value");
19551952

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

1958-
var instance = (ClassWithCustomTypeConverter)parseResult.ValueForOption("--value");
1955+
var instance = parseResult.ValueForOption(option);
19591956

19601957
instance.Values.Should().BeEquivalentTo("a", "b", "c");
19611958
}

src/System.CommandLine.Tests/ParsingValidationTests.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.IO;
88
using FluentAssertions;
99
using System.Linq;
10-
using System.Reflection;
1110
using Xunit;
1211
using Xunit.Abstractions;
1312

@@ -281,7 +280,7 @@ public void LegalFilePathsOnly_rejects_command_arguments_containing_invalid_path
281280

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

@@ -429,7 +428,7 @@ public void A_command_argument_can_be_invalid_based_on_file_or_directory_existen
429428
.Should()
430429
.HaveCount(1)
431430
.And
432-
.Contain(e => e.SymbolResult.Symbol.Name == "move" &&
431+
.Contain(e => e.SymbolResult.Symbol == command.Arguments.First() &&
433432
e.Message == $"File or directory does not exist: {path}");
434433
}
435434

0 commit comments

Comments
 (0)