Skip to content

Commit

Permalink
Add support for arrays in [DefaultValue] attributes (#1164)
Browse files Browse the repository at this point in the history
Fixes #1163
  • Loading branch information
0xced committed May 11, 2023
1 parent 6acf9b8 commit dac2097
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ private object GetLookup(CommandParameter parameter, ITypeResolver resolver, obj

private object GetArray(CommandParameter parameter, object? value)
{
if (value is Array)
{
return value;
}

// Add a new item to the array
var array = (Array?)_lookup.GetValue(parameter);
Array newArray;
Expand Down
22 changes: 21 additions & 1 deletion src/Spectre.Console.Cli/Internal/Binding/CommandValueResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,33 @@ public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeReso
var (converter, _) = GetConverter(lookup, binder, resolver, parameter);
if (converter != null)
{
result = converter.ConvertFrom(result);
result = result is Array array ? ConvertArray(array, converter) : converter.ConvertFrom(result);
}
}

return result;
}

private static Array ConvertArray(Array sourceArray, TypeConverter converter)
{
Array? targetArray = null;
for (var i = 0; i < sourceArray.Length; i++)
{
var item = sourceArray.GetValue(i);
if (item != null)
{
var converted = converter.ConvertFrom(item);
if (converted != null)
{
targetArray ??= Array.CreateInstance(converted.GetType(), sourceArray.Length);
targetArray.SetValue(converted, i);
}
}
}

return targetArray ?? sourceArray;
}

[SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")]
private static (TypeConverter? Converter, ConstructorInfo? StringConstructor) GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter)
{
Expand Down
12 changes: 11 additions & 1 deletion src/Spectre.Console.Cli/Internal/HelpWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,17 @@ static string GetOptionParts(HelpOption option)
var columns = new List<string> { GetOptionParts(option) };
if (defaultValueColumn)
{
columns.Add(option.DefaultValue == null ? " " : $"[bold]{option.DefaultValue.ToString().EscapeMarkup()}[/]");
static string Bold(object obj) => $"[bold]{obj.ToString().EscapeMarkup()}[/]";

var defaultValue = option.DefaultValue switch
{
null => " ",
"" => " ",
Array { Length: 0 } => " ",
Array array => string.Join(", ", array.Cast<object>().Select(Bold)),
_ => Bold(option.DefaultValue),
};
columns.Add(defaultValue);
}

columns.Add(option.Description?.TrimEnd('.') ?? " ");
Expand Down
5 changes: 5 additions & 0 deletions test/Spectre.Console.Cli.Tests/Data/Settings/LionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ public class LionSettings : CatSettings
[CommandOption("-c <CHILDREN>")]
[Description("The number of children the lion has.")]
public int Children { get; set; }

[CommandOption("-d <DAY>")]
[Description("The days the lion goes hunting.")]
[DefaultValue(new[] { DayOfWeek.Monday, DayOfWeek.Thursday })]
public DayOfWeek[] HuntDays { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,18 @@ public sealed class RequiredArgumentWithDefaultValueSettings : CommandSettings
[DefaultValue("Hello World")]
public string Greeting { get; set; }
}

public sealed class OptionWithArrayOfEnumDefaultValueSettings : CommandSettings
{
[CommandOption("--days")]
[DefaultValue(new[] { DayOfWeek.Sunday, DayOfWeek.Saturday })]
public DayOfWeek[] Days { get; set; }
}

public sealed class OptionWithArrayOfStringDefaultValueAndTypeConverterSettings : CommandSettings
{
[CommandOption("--numbers")]
[DefaultValue(new[] { "2", "3" })]
[TypeConverter(typeof(StringToIntegerConverter))]
public int[] Numbers { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ ARGUMENTS:

OPTIONS:
DEFAULT
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
-d <DAY> Monday, Thursday The days the lion goes hunting
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ ARGUMENTS:

OPTIONS:
DEFAULT
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
-d <DAY> Monday, Thursday The days the lion goes hunting
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ ARGUMENTS:

OPTIONS:
DEFAULT
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
-d <DAY> Monday, Thursday The days the lion goes hunting
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ ARGUMENTS:

OPTIONS:
DEFAULT
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
--agility <VALUE> 10 The agility between 0 and 100
-c <CHILDREN> The number of children the lion has
-d <DAY> Monday, Thursday The days the lion goes hunting

COMMANDS:
giraffe <LENGTH> The giraffe command
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ ARGUMENTS:
<TEETH> The number of teeth the lion has

OPTIONS:
-h, --help Prints help information
-c <CHILDREN> The number of children the lion has
DEFAULT
-h, --help Prints help information
-c <CHILDREN> The number of children the lion has
-d <DAY> Monday, Thursday The days the lion goes hunting
44 changes: 44 additions & 0 deletions test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,50 @@ public void Should_Assign_Default_Value_To_Optional_Argument_Using_Converter_If_
});
}

[Fact]
public void Should_Assign_Array_Default_Value_To_Command_Option()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<OptionWithArrayOfEnumDefaultValueSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});

// When
var result = app.Run(Array.Empty<string>());

// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionWithArrayOfEnumDefaultValueSettings>().And(settings =>
{
settings.Days.ShouldBe(new[] { DayOfWeek.Sunday, DayOfWeek.Saturday });
});
}

[Fact]
public void Should_Assign_Array_Default_Value_To_Command_Option_Using_Converter_If_Necessary()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<OptionWithArrayOfStringDefaultValueAndTypeConverterSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});

// When
var result = app.Run(Array.Empty<string>());

// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionWithArrayOfStringDefaultValueAndTypeConverterSettings>().And(settings =>
{
settings.Numbers.ShouldBe(new[] { 2, 3 });
});
}

[Fact]
public void Should_Throw_If_Required_Argument_Have_Default_Value()
{
Expand Down

0 comments on commit dac2097

Please sign in to comment.