From 4d88a6ab69734126645d59c6417adc9e082a410d Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Sun, 9 May 2021 08:50:39 +0200 Subject: [PATCH] Play nice with type converters --- .../Cli/CommandAppTests.ValueProviders.cs | 44 ++++++++++++------- .../Internal/Binding/CommandValueResolver.cs | 39 +++++++++------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/Spectre.Console.Tests/Unit/Cli/CommandAppTests.ValueProviders.cs b/src/Spectre.Console.Tests/Unit/Cli/CommandAppTests.ValueProviders.cs index 0001c56..8862d82 100644 --- a/src/Spectre.Console.Tests/Unit/Cli/CommandAppTests.ValueProviders.cs +++ b/src/Spectre.Console.Tests/Unit/Cli/CommandAppTests.ValueProviders.cs @@ -1,3 +1,6 @@ +using System; +using System.ComponentModel; +using System.Globalization; using System.Linq; using Shouldly; using Spectre.Console.Cli; @@ -15,7 +18,8 @@ namespace Spectre.Console.Tests.Unit.Cli { [CommandOption("-f|--foo ")] [IntegerValueProvider(32)] - public int Foo { get; set; } + [TypeConverter(typeof(HexConverter))] + public string Foo { get; set; } } public sealed class IntegerValueProvider : ParameterValueProviderAttribute @@ -29,13 +33,10 @@ namespace Spectre.Console.Tests.Unit.Cli public override bool TryGetValue(CommandParameterContext context, out object result) { - if (context.Parameter.ParameterType == typeof(int)) + if (context.Value == null) { - if (context.Value == null) - { - result = _value; - return true; - } + result = _value; + return true; } result = null; @@ -43,16 +44,28 @@ namespace Spectre.Console.Tests.Unit.Cli } } + public sealed class HexConverter : TypeConverter + { + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is int integer) + { + return integer.ToString("X"); + } + + return value is string stringValue && int.TryParse(stringValue, out var intValue) + ? intValue.ToString("X") + : base.ConvertFrom(context, culture, value); + } + } + [Fact] public void Should_Use_Provided_Value_If_No_Value_Was_Specified() { // Given var app = new CommandAppTester(); app.SetDefaultCommand>(); - app.Configure(config => - { - config.PropagateExceptions(); - }); + app.Configure(config => config.PropagateExceptions()); // When var result = app.Run(); @@ -60,7 +73,7 @@ namespace Spectre.Console.Tests.Unit.Cli // Then result.Settings.ShouldBeOfType().And(settings => { - settings.Foo.ShouldBe(32); + settings.Foo.ShouldBe("20"); // 32 is 0x20 }); } @@ -70,10 +83,7 @@ namespace Spectre.Console.Tests.Unit.Cli // Given var app = new CommandAppTester(); app.SetDefaultCommand>(); - app.Configure(config => - { - config.PropagateExceptions(); - }); + app.Configure(config => config.PropagateExceptions()); // When var result = app.Run("--foo", "12"); @@ -81,7 +91,7 @@ namespace Spectre.Console.Tests.Unit.Cli // Then result.Settings.ShouldBeOfType().And(settings => { - settings.Foo.ShouldBe(12); + settings.Foo.ShouldBe("C"); // 12 is 0xC }); } } diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs index 4954a25..e190752 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs @@ -24,6 +24,8 @@ namespace Spectre.Console.Cli var context = new CommandParameterContext(parameter, resolver, null); if (parameter.ValueProvider.TryGetValue(context, out var result)) { + result = ConvertValue(resolver, lookup, binder, parameter, result); + lookup.SetValue(parameter, result); CommandValidator.ValidateParameter(parameter, lookup, resolver); continue; @@ -42,16 +44,7 @@ namespace Spectre.Console.Cli if (parameter.DefaultValue != null) { var value = parameter.DefaultValue?.Value; - - // Need to convert the default value? - if (value != null && value.GetType() != parameter.ParameterType) - { - var converter = GetConverter(lookup, binder, resolver, parameter); - if (converter != null) - { - value = converter.ConvertFrom(value); - } - } + value = ConvertValue(resolver, lookup, binder, parameter, value); binder.Bind(parameter, resolver, value); CommandValidator.ValidateParameter(parameter, lookup, resolver); @@ -74,12 +67,6 @@ namespace Spectre.Console.Cli } else { - var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); - if (converter == null) - { - throw CommandRuntimeException.NoConverterFound(mapped.Parameter); - } - if (mapped.Parameter.IsFlagValue() && mapped.Value == null) { if (mapped.Parameter is CommandOption option && option.DefaultValue != null) @@ -95,6 +82,12 @@ namespace Spectre.Console.Cli } else { + var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); + if (converter == null) + { + throw CommandRuntimeException.NoConverterFound(mapped.Parameter); + } + // Assign the value to the parameter. binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value)); } @@ -119,6 +112,20 @@ namespace Spectre.Console.Cli return lookup; } + private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result) + { + if (result != null && result.GetType() != parameter.ParameterType) + { + var converter = GetConverter(lookup, binder, resolver, parameter); + if (converter != null) + { + result = converter.ConvertFrom(result); + } + } + + return result; + } + [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) {