From b10e80222377889c3244e23a7c18a338551114ad Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Sun, 30 Aug 2020 14:03:45 +0800 Subject: [PATCH 1/2] fix https://github.com/natemcmaster/CommandLineUtils/issues/388 --- .../HelpText/DefaultHelpTextGenerator.cs | 19 +++++++++++-- .../Internal/ReflectionHelper.cs | 10 +++++++ .../DefaultHelpTextGeneratorTests.cs | 28 +++++++++++++++++-- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs b/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs index 6c5665bc..2732d6b6 100644 --- a/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs +++ b/src/CommandLineUtils/HelpText/DefaultHelpTextGenerator.cs @@ -386,12 +386,27 @@ protected virtual string Format(CommandOption option) private string[] ExtractNamesFromEnum(Type type) { - if (type == null || !type.IsEnum) + if (type == null) { return Util.EmptyArray(); } - return Enum.GetNames(type); + if (ReflectionHelper.IsNullableType(type, out Type wrappedType)) + { + return ExtractNamesFromEnum(wrappedType); + } + + if (ReflectionHelper.IsSpecialValueTupleType(type, out var fieldInfo)) + { + return ExtractNamesFromEnum(fieldInfo.FieldType); + } + + if (type.IsEnum) + { + return Enum.GetNames(type); + } + + return Util.EmptyArray(); } } } diff --git a/src/CommandLineUtils/Internal/ReflectionHelper.cs b/src/CommandLineUtils/Internal/ReflectionHelper.cs index a3785611..b3f6f729 100644 --- a/src/CommandLineUtils/Internal/ReflectionHelper.cs +++ b/src/CommandLineUtils/Internal/ReflectionHelper.cs @@ -105,6 +105,16 @@ public static bool IsNullableType(Type type, out Type? wrappedType) return result; } + public static bool IsSpecialValueTupleType(Type type, out FieldInfo fieldInfo) + { + var result = type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(ValueTuple<,>) && + type.GenericTypeArguments[0] == typeof(bool); + fieldInfo = result ? type.GetFields()[1] : null; + + return result; + } + private static IEnumerable GetAllMembers(Type type) { while (type != null) diff --git a/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs b/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs index 4e03dc16..d443a22d 100644 --- a/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs +++ b/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs @@ -112,12 +112,15 @@ public void ShowHelp() app.Option("--rStrOpt ", "restricted str option desc.", CommandOptionType.SingleValue, o => o.IsRequired().Accepts().Values("Foo", "Bar")); app.Option("--intOpt ", "int option desc.", CommandOptionType.SingleValue); app.Option("--enumOpt ", "enum option desc.", CommandOptionType.SingleValue); + app.Option<(bool, SomeEnum)>("--enumOpt2 ", "nullable enum option desc.", CommandOptionType.SingleOrNoValue); + app.Option("--enumOpt3 ", "nullable enum option desc.", CommandOptionType.SingleOrNoValue); app.Argument("SomeStringArgument", "string arg desc."); app.Argument("RestrictedStringArgument", "restricted string arg desc.", a => a.IsRequired().Accepts().Values("Foo", "Bar")); app.Argument("SomeEnumArgument", "enum arg desc."); + app.Argument<(bool, SomeEnum)>("SomeNullableEnumArgument", "nullable enum arg desc."); var helpText = GetHelpText(app); - Assert.Equal(@"Usage: [options] + Assert.Equal(@"Usage: [options] Arguments: SomeStringArgument string arg desc. @@ -125,6 +128,8 @@ RestrictedStringArgument restricted string arg desc. Allowed values are: Foo, Bar. SomeEnumArgument enum arg desc. Allowed values are: None, Normal, Extreme. + SomeNullableEnumArgument nullable enum arg desc. + Allowed values are: None, Normal, Extreme. Options: -?|-h|--help Show help information. @@ -134,6 +139,10 @@ SomeEnumArgument enum arg desc. --intOpt int option desc. --enumOpt enum option desc. Allowed values are: None, Normal, Extreme. + --enumOpt2[:] nullable enum option desc. + Allowed values are: None, Normal, Extreme. + --enumOpt3[:] nullable enum option desc. + Allowed values are: None, Normal, Extreme. ", helpText, @@ -148,7 +157,7 @@ public void ShowHelpFromAttributes() app.Conventions.UseDefaultConventions(); var helpText = GetHelpText(app); - Assert.Equal(@"Usage: test [options] + Assert.Equal(@"Usage: test [options] Arguments: SomeStringArgument string arg desc. @@ -156,6 +165,8 @@ RestrictedStringArgument restricted string arg desc. Allowed values are: Foo, Bar. SomeEnumArgument enum arg desc. Allowed values are: None, Normal, Extreme. + SomeNullableEnumArgument nullable enum arg desc. + Allowed values are: None, Normal, Extreme. Options: -strOpt|--str-opt str option desc. @@ -164,6 +175,10 @@ SomeEnumArgument enum arg desc. -intOpt|--int-opt int option desc. -enumOpt|--verbosity enum option desc. Allowed values are: None, Normal, Extreme. + -enumOpt2|--verb2[:] nullable enum option desc. + Allowed values are: None, Normal, Extreme. + -enumOpt3|--verb3[:] nullable enum option desc. + Allowed values are: None, Normal, Extreme. -?|-h|--help Show help information. ", @@ -187,6 +202,12 @@ public class MyApp [Option(ShortName = "enumOpt", Description = "enum option desc.")] public SomeEnum Verbosity { get; set; } + [Option(ShortName = "enumOpt2", Description = "nullable enum option desc.")] + public (bool HasValue, SomeEnum Value) Verb2 { get; set; } + + [Option(CommandOptionType.SingleOrNoValue, ShortName = "enumOpt3", Description = "nullable enum option desc.")] + public SomeEnum? Verb3 { get; set; } + [Argument(0, Description = "string arg desc.")] public string SomeStringArgument { get; set; } @@ -197,6 +218,9 @@ public class MyApp [Argument(2, Description = "enum arg desc.")] public SomeEnum SomeEnumArgument { get; set; } + + [Argument(3, Description = "nullable enum arg desc.")] + public (bool HasValue, SomeEnum Value) SomeNullableEnumArgument { get; set; } } [Theory] From 6f96a5c7022986ee038713e6d84d8129a834322f Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Sun, 13 Sep 2020 08:14:31 +0800 Subject: [PATCH 2/2] Fix UT --- test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs b/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs index 48c8ff9b..1a0c3df2 100644 --- a/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs +++ b/test/CommandLineUtils.Tests/DefaultHelpTextGeneratorTests.cs @@ -185,9 +185,9 @@ SomeNullableEnumArgument nullable enum arg desc. Allowed values are: None, Normal, Extreme. -enumOpt2|--verb2 restricted enum option desc. Allowed values are: None, Normal. - -enumOpt3|--verb2[:] nullable enum option desc. + -enumOpt3|--verb3[:] nullable enum option desc. Allowed values are: None, Normal, Extreme. - -enumOpt4|--verb3[:] nullable enum option desc. + -enumOpt4|--verb4[:] nullable enum option desc. Allowed values are: None, Normal, Extreme. -?|-h|--help Show help information.