From c53acce3145bef93e3652be535245d6d6d17041c Mon Sep 17 00:00:00 2001 From: "Moh.Hassan" Date: Sun, 2 Jun 2019 14:37:25 +0200 Subject: [PATCH] fix issue #104 of nullable enum --- src/CommandLine/Core/Specification.cs | 6 +- .../Infrastructure/ReflectionHelper.cs | 20 ++++-- ...ions_With_Nullable_Enum_Having_HelpText.cs | 13 ++++ tests/CommandLine.Tests/Unit/Issue104Tests.cs | 68 +++++++++++++++++++ 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 tests/CommandLine.Tests/Fakes/Options_With_Nullable_Enum_Having_HelpText.cs create mode 100644 tests/CommandLine.Tests/Unit/Issue104Tests.cs diff --git a/src/CommandLine/Core/Specification.cs b/src/CommandLine/Core/Specification.cs index 9b267741..b95b998c 100644 --- a/src/CommandLine/Core/Specification.cs +++ b/src/CommandLine/Core/Specification.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using CommandLine.Infrastructure; using CSharpx; namespace CommandLine.Core @@ -115,9 +116,8 @@ public static Specification FromProperty(PropertyInfo property) if (oa.Count() == 1) { var spec = OptionSpecification.FromAttribute(oa.Single(), property.PropertyType, - property.PropertyType.GetTypeInfo().IsEnum - ? Enum.GetNames(property.PropertyType) - : Enumerable.Empty()); + ReflectionHelper.GetNamesOfEnum(property.PropertyType)); + if (spec.ShortName.Length == 0 && spec.LongName.Length == 0) { return spec.WithLongName(property.Name.ToLowerInvariant()); diff --git a/src/CommandLine/Infrastructure/ReflectionHelper.cs b/src/CommandLine/Infrastructure/ReflectionHelper.cs index e2177947..a7926cb7 100644 --- a/src/CommandLine/Infrastructure/ReflectionHelper.cs +++ b/src/CommandLine/Infrastructure/ReflectionHelper.cs @@ -45,10 +45,10 @@ public static Maybe GetAttribute() // Test support if (_overrides != null) { - return + return _overrides.ContainsKey(typeof(TAttribute)) ? Maybe.Just((TAttribute)_overrides[typeof(TAttribute)]) : - Maybe.Nothing< TAttribute>(); + Maybe.Nothing(); } var assembly = GetExecutingOrEntryAssembly(); @@ -84,7 +84,7 @@ public static bool IsFSharpOptionType(Type type) public static T CreateDefaultImmutableInstance(Type[] constructorTypes) { - var t = typeof(T); + var t = typeof(T); return (T)CreateDefaultImmutableInstance(t, constructorTypes); } @@ -100,7 +100,17 @@ private static Assembly GetExecutingOrEntryAssembly() { //resolve issues of null EntryAssembly in Xunit Test #392,424,389 //return Assembly.GetEntryAssembly(); - return Assembly.GetEntryAssembly()??Assembly.GetCallingAssembly(); + return Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly(); + } + + public static IEnumerable GetNamesOfEnum(Type t) + { + if (t.IsEnum) + return Enum.GetNames(t); + Type u = Nullable.GetUnderlyingType(t); + if (u != null && u.IsEnum) + return Enum.GetNames(u); + return Enumerable.Empty(); } } -} \ No newline at end of file +} diff --git a/tests/CommandLine.Tests/Fakes/Options_With_Nullable_Enum_Having_HelpText.cs b/tests/CommandLine.Tests/Fakes/Options_With_Nullable_Enum_Having_HelpText.cs new file mode 100644 index 00000000..a316124e --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Options_With_Nullable_Enum_Having_HelpText.cs @@ -0,0 +1,13 @@ +// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. + +namespace CommandLine.Tests.Fakes +{ + class Options_With_Nullable_Enum_Having_HelpText + { + [Option(HelpText = "Define a string value here.")] + public string StringValue { get; set; } + + [Option(HelpText="Define a enum value here.")] + public Shapes? Shape { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Unit/Issue104Tests.cs b/tests/CommandLine.Tests/Unit/Issue104Tests.cs new file mode 100644 index 00000000..fcbefedd --- /dev/null +++ b/tests/CommandLine.Tests/Unit/Issue104Tests.cs @@ -0,0 +1,68 @@ +using System.Linq; +using CommandLine.Tests.Fakes; +using CommandLine.Text; +using FluentAssertions; +using Xunit; +using Xunit.Abstractions; + +//Issue #104 +//When outputting HelpText, the code will correctly list valid values for enum type options. However, if the option is a nullable enum type, then it will not list the valid values. + +namespace CommandLine.Tests.Unit +{ + public class Issue104Tests + { + + [Fact] + public void Create_instance_with_enum_options_enabled_and_nullable_enum() + { + // Fixture setup + // Exercize system + var sut = new HelpText { AddDashesToOption = true, AddEnumValuesToHelpText = true, MaximumDisplayWidth = 80 } + .AddPreOptionsLine("pre-options") + .AddOptions(new NotParsed(TypeInfo.Create(typeof(Options_With_Enum_Having_HelpText)), Enumerable.Empty())) + .AddPostOptionsLine("post-options"); + + // Verify outcome + + var lines = sut.ToString().ToNotEmptyLines().TrimStringArray(); + lines[0].Should().BeEquivalentTo("pre-options"); + lines[1].Should().BeEquivalentTo("--stringvalue Define a string value here."); + lines[2].Should().BeEquivalentTo("--shape Define a enum value here. Valid values: Circle, Square,"); + lines[3].Should().BeEquivalentTo("Triangle"); + lines[4].Should().BeEquivalentTo("--help Display this help screen."); + lines[5].Should().BeEquivalentTo("--version Display version information."); + lines[6].Should().BeEquivalentTo("post-options"); + // Teardown + } + + [Fact] + public void Help_with_enum_options_enabled_and_nullable_enum() + { + // Fixture setup + // Exercize system + var args = "--help".Split(); + var sut = new Parser(config => config.HelpWriter = null); + var parserResult = sut.ParseArguments(args); + HelpText helpText = null; + parserResult.WithNotParsed(errors => + { + // Use custom help text to ensure valid enum values are displayed + helpText = HelpText.AutoBuild(parserResult); + helpText.AddEnumValuesToHelpText = true; + helpText.AddOptions(parserResult); + }); + + // Verify outcome + + var lines = helpText.ToString().ToNotEmptyLines().TrimStringArray(); + lines[2].Should().BeEquivalentTo("--stringvalue Define a string value here."); + lines[3].Should().BeEquivalentTo("--shape Define a enum value here. Valid values: Circle, Square,"); + lines[4].Should().BeEquivalentTo("Triangle"); + lines[5].Should().BeEquivalentTo("--help Display this help screen."); + lines[6].Should().BeEquivalentTo("--version Display version information."); + // Teardown + } + } + +}