Skip to content

Commit 72e86ec

Browse files
authored
Model binding should follow default values (#1250)
1 parent 722ada8 commit 72e86ec

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,86 @@ public void Explicit_model_binder_binds_only_to_configured_ctor_parameters()
547547
instance.StringOption.Should().Be("the default");
548548
}
549549

550+
[Fact]
551+
public async Task Bound_array_command_arguments_default_to_an_empty_array_when_not_specified()
552+
{
553+
var rootCommand = new RootCommand("Command")
554+
{
555+
new Argument<string[]>("names"),
556+
};
557+
rootCommand.Handler = CommandHandler.Create<string[]>(Handler);
558+
string[] passedNames = null;
559+
await rootCommand.InvokeAsync("");
560+
561+
passedNames.Should().BeEmpty();
562+
563+
int Handler(string[] names)
564+
{
565+
passedNames = names;
566+
return 0;
567+
}
568+
}
569+
570+
[Fact]
571+
public async Task Bound_enumerable_command_arguments_default_to_an_empty_array_when_not_specified()
572+
{
573+
var rootCommand = new RootCommand("Command")
574+
{
575+
new Argument<IEnumerable<string>>("names"),
576+
};
577+
rootCommand.Handler = CommandHandler.Create<IEnumerable<string>>(Handler);
578+
IEnumerable<string> passedNames = null;
579+
await rootCommand.InvokeAsync("");
580+
581+
passedNames.Should().BeEmpty();
582+
583+
int Handler(IEnumerable<string> names)
584+
{
585+
passedNames = names;
586+
return 0;
587+
}
588+
}
589+
590+
[Fact]
591+
public async Task Bound_array_options_default_to_an_empty_array_when_not_specified()
592+
{
593+
var rootCommand = new RootCommand("Command")
594+
{
595+
new Option<string[]>("--names"),
596+
};
597+
rootCommand.Handler = CommandHandler.Create<string[]>(Handler);
598+
string[] passedNames = null;
599+
await rootCommand.InvokeAsync("");
600+
601+
passedNames.Should().BeEmpty();
602+
603+
int Handler(string[] names)
604+
{
605+
passedNames = names;
606+
return 0;
607+
}
608+
}
609+
610+
[Fact]
611+
public async Task Bound_enumerable_options_default_to_an_empty_array_when_not_specified()
612+
{
613+
var rootCommand = new RootCommand("Command")
614+
{
615+
new Option<IEnumerable<string>>("--names"),
616+
};
617+
rootCommand.Handler = CommandHandler.Create<IEnumerable<string>>(Handler);
618+
IEnumerable<string> passedNames = null;
619+
await rootCommand.InvokeAsync("");
620+
621+
passedNames.Should().BeEmpty();
622+
623+
int Handler(IEnumerable<string> names)
624+
{
625+
passedNames = names;
626+
return 0;
627+
}
628+
}
629+
550630
[Fact]
551631
public void Custom_ModelBinders_specified_via_BindingContext_can_be_used_for_option_binding()
552632
{
@@ -628,8 +708,6 @@ public void Default_values_from_options_with_the_same_type_are_bound_and_use_the
628708
second.Should().Be(2);
629709
}
630710

631-
632-
633711
[Fact]
634712
public void Binder_does_not_match_on_partial_name()
635713
{

src/System.CommandLine/Parsing/CommandResultExtensions.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ internal static bool TryGetValueForArgument(
1919

2020
if (valueDescriptor.ValueName.IsMatch(argument.Name))
2121
{
22-
value = commandResult.FindResultFor(argument)?.GetValueOrDefault();
22+
if (commandResult.FindResultFor(argument) is { } argumentResult)
23+
{
24+
value = argumentResult.GetValueOrDefault();
25+
}
26+
else
27+
{
28+
value = valueDescriptor.GetDefaultValue();
29+
}
2330
return true;
2431
}
2532
}

0 commit comments

Comments
 (0)