From 3e33477b03aea1521025823fb053af72da432513 Mon Sep 17 00:00:00 2001 From: njonesu Date: Sat, 1 Jun 2019 17:29:44 +0200 Subject: [PATCH 1/3] Add test for issue --- tests/CommandLine.Tests/Fakes/Help_Fakes.cs | 22 +++++++++++++++++++ .../Unit/Text/HelpTextTests.cs | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/CommandLine.Tests/Fakes/Help_Fakes.cs b/tests/CommandLine.Tests/Fakes/Help_Fakes.cs index cceb5331..87af6847 100644 --- a/tests/CommandLine.Tests/Fakes/Help_Fakes.cs +++ b/tests/CommandLine.Tests/Fakes/Help_Fakes.cs @@ -93,6 +93,28 @@ public static IEnumerable Examples } } + class Required_Enum_Option_With_Usage_Attribute + { + [Option('t', "type", Required = true, HelpText = "My entity")] + public EntityType MyEntityType { get; set; } + + public enum EntityType + { + T0, + T1 + } + + [Usage(ApplicationAlias = "testapp.exe")] + public static IEnumerable Examples + { + get + { + yield return new Example(EntityType.T0.ToString(), new Required_Enum_Option_With_Usage_Attribute { MyEntityType = EntityType.T0 }); + yield return new Example(EntityType.T1.ToString(), new Required_Enum_Option_With_Usage_Attribute { MyEntityType = EntityType.T1 }); + } + } + } + [Verb("secert", Hidden = true, HelpText = "This is a secert hidden verb that should never be visible to the user via help text.")] public class Secert_Verb { diff --git a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs index 7c4d7590..6e4051a8 100644 --- a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs +++ b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs @@ -494,6 +494,28 @@ public static void RenderUsageText_returns_properly_formatted_text() lines[10].Should().BeEquivalentTo(" mono testapp.exe value"); } + [Fact] + public static void RenderUsageText_returns_proper_text_for_required_enum_option() + { + // Fixture setup + ParserResult result = + new NotParsed( + TypeInfo.Create(typeof(Required_Enum_Option_With_Usage_Attribute)), Enumerable.Empty()); + + // Exercize system + var text = HelpText.RenderUsageText(result); + + // Verify outcome + var lines = text.ToNotEmptyLines(); + + lines[0].Should().BeEquivalentTo("T0:"); + lines[1].Should().BeEquivalentTo(" testapp.exe --type T0"); + lines[2].Should().BeEquivalentTo("T1:"); + lines[3].Should().BeEquivalentTo(" testapp.exe --type T1"); + + // Teardown + } + //[Fact] public void Invoke_AutoBuild_for_Options_with_Usage_returns_appropriate_formatted_text() { From 62467e4ef48cb6c40b23d3a39d7415647b3e0e09 Mon Sep 17 00:00:00 2001 From: njonesu Date: Sat, 1 Jun 2019 17:49:19 +0200 Subject: [PATCH 2/3] Bug fix --- src/CommandLine/UnParserExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CommandLine/UnParserExtensions.cs b/src/CommandLine/UnParserExtensions.cs index 7db948e7..73b704c7 100644 --- a/src/CommandLine/UnParserExtensions.cs +++ b/src/CommandLine/UnParserExtensions.cs @@ -248,6 +248,7 @@ private static bool IsEmpty(this object value) #if !SKIP_FSHARP if (ReflectionHelper.IsFSharpOptionType(value.GetType()) && !FSharpOptionHelper.IsSome(value)) return true; #endif + if (value is Enum) return false; if (value is ValueType && value.Equals(value.GetType().GetDefaultValue())) return true; if (value is string && ((string)value).Length == 0) return true; if (value is IEnumerable && !((IEnumerable)value).GetEnumerator().MoveNext()) return true; From baed89cd18c14c68262722c29be2b2d74c34fbfa Mon Sep 17 00:00:00 2001 From: njonesu Date: Tue, 11 Jun 2019 15:11:12 +0200 Subject: [PATCH 3/3] Include only required value types with default value --- src/CommandLine/UnParserExtensions.cs | 7 +++--- tests/CommandLine.Tests/Fakes/Help_Fakes.cs | 22 +++++++++++++------ .../Unit/Text/HelpTextTests.cs | 16 +++++++------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/CommandLine/UnParserExtensions.cs b/src/CommandLine/UnParserExtensions.cs index 73b704c7..c23bca8e 100644 --- a/src/CommandLine/UnParserExtensions.cs +++ b/src/CommandLine/UnParserExtensions.cs @@ -121,7 +121,7 @@ public static string FormatCommandLine(this Parser parser, T options, Action< type.GetSpecifications( pi => new { Specification = Specification.FromProperty(pi), Value = pi.GetValue(options, null).NormalizeValue(), PropertyValue = pi.GetValue(options, null) }) - where !info.PropertyValue.IsEmpty() + where !info.PropertyValue.IsEmpty(info.Specification) select info) .Memorize(); @@ -242,14 +242,13 @@ private static object NormalizeValue(this object value) return value; } - private static bool IsEmpty(this object value) + private static bool IsEmpty(this object value, Specification spec) { if (value == null) return true; #if !SKIP_FSHARP if (ReflectionHelper.IsFSharpOptionType(value.GetType()) && !FSharpOptionHelper.IsSome(value)) return true; #endif - if (value is Enum) return false; - if (value is ValueType && value.Equals(value.GetType().GetDefaultValue())) return true; + if (!spec.Required && value is ValueType && value.Equals(value.GetType().GetDefaultValue())) return true; if (value is string && ((string)value).Length == 0) return true; if (value is IEnumerable && !((IEnumerable)value).GetEnumerator().MoveNext()) return true; return false; diff --git a/tests/CommandLine.Tests/Fakes/Help_Fakes.cs b/tests/CommandLine.Tests/Fakes/Help_Fakes.cs index 87af6847..4cb0c748 100644 --- a/tests/CommandLine.Tests/Fakes/Help_Fakes.cs +++ b/tests/CommandLine.Tests/Fakes/Help_Fakes.cs @@ -93,24 +93,32 @@ public static IEnumerable Examples } } - class Required_Enum_Option_With_Usage_Attribute + class Options_With_Default_Value_Examples { - [Option('t', "type", Required = true, HelpText = "My entity")] + [Option('t', "type", Required = true)] public EntityType MyEntityType { get; set; } public enum EntityType { - T0, - T1 + T0 } - [Usage(ApplicationAlias = "testapp.exe")] + [Option('i', "int", Required = true)] + public int Int { get; set; } + + [Option('d', "double", Required = true)] + public double Double { get; set; } + + [Option('o', "optional")] + public bool Optional { get; set; } + + [Usage(ApplicationAlias = "mono testapp.exe")] public static IEnumerable Examples { get { - yield return new Example(EntityType.T0.ToString(), new Required_Enum_Option_With_Usage_Attribute { MyEntityType = EntityType.T0 }); - yield return new Example(EntityType.T1.ToString(), new Required_Enum_Option_With_Usage_Attribute { MyEntityType = EntityType.T1 }); + yield return new Example("Normal scenario", new Options_With_Default_Value_Examples { }); + yield return new Example("With Optional Value", new Options_With_Default_Value_Examples { Optional = true }); } } } diff --git a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs index 6e4051a8..7362d9e0 100644 --- a/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs +++ b/tests/CommandLine.Tests/Unit/Text/HelpTextTests.cs @@ -495,12 +495,12 @@ public static void RenderUsageText_returns_properly_formatted_text() } [Fact] - public static void RenderUsageText_returns_proper_text_for_required_enum_option() + public static void RenderUsageText_returns_proper_text_for_Examples_with_default_values() { // Fixture setup - ParserResult result = - new NotParsed( - TypeInfo.Create(typeof(Required_Enum_Option_With_Usage_Attribute)), Enumerable.Empty()); + ParserResult result = + new NotParsed( + TypeInfo.Create(typeof(Options_With_Default_Value_Examples)), Enumerable.Empty()); // Exercize system var text = HelpText.RenderUsageText(result); @@ -508,10 +508,10 @@ public static void RenderUsageText_returns_proper_text_for_required_enum_option( // Verify outcome var lines = text.ToNotEmptyLines(); - lines[0].Should().BeEquivalentTo("T0:"); - lines[1].Should().BeEquivalentTo(" testapp.exe --type T0"); - lines[2].Should().BeEquivalentTo("T1:"); - lines[3].Should().BeEquivalentTo(" testapp.exe --type T1"); + lines[0].Should().BeEquivalentTo("Normal scenario:"); + lines[1].Should().BeEquivalentTo(" mono testapp.exe --double 0 --int 0 --type T0"); + lines[2].Should().BeEquivalentTo("With Optional Value:"); + lines[3].Should().BeEquivalentTo(" mono testapp.exe --double 0 --int 0 --optional --type T0"); // Teardown }