From be9010e01b1d1c2d2f84f3ba6b8e4dbfb62db307 Mon Sep 17 00:00:00 2001 From: Mohamed Hassan Date: Mon, 13 Jan 2020 00:10:42 +0200 Subject: [PATCH 1/5] Add MyGet package provider to consume the daily builds. (#566) --- appveyor.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 827ded7f..e9af5e38 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,12 +1,12 @@ #version should be only changed with RELEASE eminent, see RELEASE.md -version: 2.7.83-beta-{build} +version: 2.7.84-beta-{build} image: Visual Studio 2019 clone_depth: 1 pull_requests: - do_not_increment_build_number: true + do_not_increment_build_number: false init: - ps: | @@ -15,8 +15,9 @@ init: if ($env:APPVEYOR_REPO_TAG -eq "true") { $ver = $env:APPVEYOR_REPO_TAG_NAME if($ver.StartsWith("v") -eq $true) { $ver = $ver.Substring(1) } - Update-AppveyorBuild -Version $ver - } + Update-AppveyorBuild -Version $ver + } + - ps: Write-Host "APPVEYOR_BUILD_VERSION='$env:APPVEYOR_BUILD_VERSION'" -ForegroundColor Yellow environment: matrix: @@ -57,3 +58,12 @@ deploy: artifact: 'NuGetPackages' on: APPVEYOR_REPO_TAG: true + +#myget +- provider: NuGet + server: https://www.myget.org/F/commandlineparser/api/v2/package + api_key: + secure: ltHh/DsAk+Y7qbJwzUO4+i1U+7uGTLVYXTdW0+Rk2z7jqj5DDNNlih9J8K7bU4bH + artifact: 'NuGetPackages' + symbol_server: https://www.myget.org/F/commandlineparser/symbols/api/v2/package + From 13a1159149feab67f5001cbac0794a6757b7d1f3 Mon Sep 17 00:00:00 2001 From: Vladislav Hadzhiyski Date: Sun, 2 Feb 2020 18:14:41 +0200 Subject: [PATCH 2/5] Options groups take in account default value --- src/CommandLine/Core/SpecificationPropertyRules.cs | 5 +++-- ...ions_With_OptionGroup_WithOptionDefaultValue.cs | 14 ++++++++++++++ .../Unit/Core/InstanceBuilderTests.cs | 10 ++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_WithOptionDefaultValue.cs diff --git a/src/CommandLine/Core/SpecificationPropertyRules.cs b/src/CommandLine/Core/SpecificationPropertyRules.cs index 9122ee3a..d287e67f 100644 --- a/src/CommandLine/Core/SpecificationPropertyRules.cs +++ b/src/CommandLine/Core/SpecificationPropertyRules.cs @@ -36,14 +36,15 @@ where o.Group.Length > 0 select new { Option = o, - Value = sp.Value + Value = sp.Value, + DefaultValue = sp.Specification.DefaultValue }; var groups = from o in optionsValues group o by o.Option.Group into g select g; - var errorGroups = groups.Where(gr => gr.All(g => g.Value.IsNothing())); + var errorGroups = groups.Where(gr => gr.All(g => g.Value.IsNothing() && g.DefaultValue.IsNothing())); if (errorGroups.Any()) { diff --git a/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_WithOptionDefaultValue.cs b/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_WithOptionDefaultValue.cs new file mode 100644 index 00000000..9ae3a59e --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_WithOptionDefaultValue.cs @@ -0,0 +1,14 @@ +namespace CommandLine.Tests.Fakes +{ + public class Simple_Options_With_OptionGroup_WithOptionDefaultValue + { + [Option(HelpText = "Define a string value here.", Required = true, Group = "test", Default = "qwerty123")] + public string StringValue { get; set; } + + [Option('s', "shortandlong", HelpText = "Example with both short and long name.", Required = true, Group = "test")] + public string ShortAndLong { get; set; } + + [Option('x', HelpText = "Define a boolean or switch value here.")] + public bool BoolValue { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index c2cbb77a..9ca4b74b 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -1164,6 +1164,16 @@ public void Options_In_Group_Ignore_Option_Group_If_Option_Group_Name_Empty() errors.Should().BeEquivalentTo(expectedResult); } + [Fact] + public void Options_In_Group_Use_Option_Default_Value_When_Available() + { + // Exercize system + var result = InvokeBuild(new string[] { "-x" }); + + // Verify outcome + result.Should().BeOfType>(); + } + private class ValueWithNoSetterOptions { [Value(0, MetaName = "Test", Default = 0)] From 6e229b9c3c62d11cf33ee031ba101927f2e01710 Mon Sep 17 00:00:00 2001 From: Vladislav Hadzhiyski Date: Sun, 2 Feb 2020 18:15:36 +0200 Subject: [PATCH 3/5] Do not allow options groups and exclusive set names to be used together --- .../Core/SpecificationPropertyRules.cs | 23 +++++++++++++++++++ src/CommandLine/Error.cs | 14 +++++++++-- ...s_With_OptionGroup_MutuallyExclusiveSet.cs | 14 +++++++++++ .../Unit/Core/InstanceBuilderTests.cs | 19 +++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_MutuallyExclusiveSet.cs diff --git a/src/CommandLine/Core/SpecificationPropertyRules.cs b/src/CommandLine/Core/SpecificationPropertyRules.cs index d287e67f..5dc1a406 100644 --- a/src/CommandLine/Core/SpecificationPropertyRules.cs +++ b/src/CommandLine/Core/SpecificationPropertyRules.cs @@ -18,12 +18,35 @@ public static IEnumerable, IEnumerable, IEnumerable> EnforceMutuallyExclusiveSetAndGroupAreNotUsedTogether() + { + return specProps => + { + var options = + from sp in specProps + where sp.Specification.IsOption() + let o = (OptionSpecification)sp.Specification + where o.SetName.Length > 0 + where o.Group.Length > 0 + select o; + + if (options.Any()) + { + return from o in options + select new GroupOptionAmbiguityError(new NameInfo(o.ShortName, o.LongName)); + } + + return Enumerable.Empty(); + }; + } + private static Func, IEnumerable> EnforceGroup() { return specProps => diff --git a/src/CommandLine/Error.cs b/src/CommandLine/Error.cs index e54dbf6a..042a92d9 100644 --- a/src/CommandLine/Error.cs +++ b/src/CommandLine/Error.cs @@ -74,8 +74,11 @@ public enum ErrorType /// /// Value of type. /// - MissingGroupOptionError - + MissingGroupOptionError, + /// + /// Value of type. + /// + GroupOptionAmbiguityError } /// @@ -556,4 +559,11 @@ public IEnumerable Names get { return names; } } } + + public sealed class GroupOptionAmbiguityError : NamedError + { + internal GroupOptionAmbiguityError(NameInfo option) + : base(ErrorType.GroupOptionAmbiguityError, option) + { } + } } diff --git a/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_MutuallyExclusiveSet.cs b/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_MutuallyExclusiveSet.cs new file mode 100644 index 00000000..52ead41c --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Simple_Options_With_OptionGroup_MutuallyExclusiveSet.cs @@ -0,0 +1,14 @@ +namespace CommandLine.Tests.Fakes +{ + public class Simple_Options_With_OptionGroup_MutuallyExclusiveSet + { + [Option(HelpText = "Define a string value here.", Group = "test", SetName = "setname", Default = "qwerty123")] + public string StringValue { get; set; } + + [Option('s', "shortandlong", HelpText = "Example with both short and long name.", Group = "test", SetName = "setname")] + public string ShortAndLong { get; set; } + + [Option('x', HelpText = "Define a boolean or switch value here.")] + public bool BoolValue { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 9ca4b74b..1f136b66 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -1174,6 +1174,25 @@ public void Options_In_Group_Use_Option_Default_Value_When_Available() result.Should().BeOfType>(); } + [Fact] + public void Options_In_Group_Do_Not_Allow_Mutually_Exclusive_Set() + { + var expectedResult = new[] + { + new GroupOptionAmbiguityError(new NameInfo("", "stringvalue")), + new GroupOptionAmbiguityError(new NameInfo("s", "shortandlong")) + }; + + // Exercize system + var result = InvokeBuild(new string[] { "-x" }); + + // Verify outcome + result.Should().BeOfType>(); + var errors = ((NotParsed)result).Errors; + + errors.Should().BeEquivalentTo(expectedResult); + } + private class ValueWithNoSetterOptions { [Value(0, MetaName = "Test", Default = 0)] From d4dc042857bea5bd5404b2da1ae68ce813778bfc Mon Sep 17 00:00:00 2001 From: Vladislav Hadzhiyski Date: Sun, 2 Feb 2020 18:25:56 +0200 Subject: [PATCH 4/5] Multiple group errors are shown together --- src/CommandLine/Error.cs | 23 ++++++++++++++- .../Fakes/Options_With_Multiple_Groups.cs | 20 +++++++++++++ .../Unit/Core/InstanceBuilderTests.cs | 28 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/CommandLine.Tests/Fakes/Options_With_Multiple_Groups.cs diff --git a/src/CommandLine/Error.cs b/src/CommandLine/Error.cs index 042a92d9..c07bb2d1 100644 --- a/src/CommandLine/Error.cs +++ b/src/CommandLine/Error.cs @@ -535,7 +535,7 @@ internal InvalidAttributeConfigurationError() } } - public sealed class MissingGroupOptionError : Error + public sealed class MissingGroupOptionError : Error, IEquatable, IEquatable { public const string ErrorMessage = "At least one option in a group must have value."; @@ -558,6 +558,27 @@ public IEnumerable Names { get { return names; } } + + public new bool Equals(Error obj) + { + var other = obj as MissingGroupOptionError; + if (other != null) + { + return Equals(other); + } + + return base.Equals(obj); + } + + public bool Equals(MissingGroupOptionError other) + { + if (other == null) + { + return false; + } + + return Group.Equals(other.Group); + } } public sealed class GroupOptionAmbiguityError : NamedError diff --git a/tests/CommandLine.Tests/Fakes/Options_With_Multiple_Groups.cs b/tests/CommandLine.Tests/Fakes/Options_With_Multiple_Groups.cs new file mode 100644 index 00000000..8f2d21ab --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Options_With_Multiple_Groups.cs @@ -0,0 +1,20 @@ +namespace CommandLine.Tests.Fakes +{ + public class Options_With_Multiple_Groups + { + [Option('v', "version")] + public string Version { get; set; } + + [Option("option11", Group = "err-group")] + public string Option11 { get; set; } + + [Option("option12", Group = "err-group")] + public string Option12 { get; set; } + + [Option("option21", Group = "err-group2")] + public string Option21 { get; set; } + + [Option("option22", Group = "err-group2")] + public string Option22 { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 1f136b66..1792fef6 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -1110,6 +1110,34 @@ public void Options_In_Group_With_No_Values_Generates_MissingGroupOptionError() ((NotParsed)result).Errors.Should().BeEquivalentTo(expectedResult); } + [Fact] + public void Options_In_Group_With_No_Values_Generates_MissingGroupOptionErrors() + { + // Fixture setup + var optionNames1 = new List + { + new NameInfo("", "option11"), + new NameInfo("", "option12") + }; + var optionNames2 = new List + { + new NameInfo("", "option21"), + new NameInfo("", "option22") + }; + var expectedResult = new[] + { + new MissingGroupOptionError("err-group", optionNames1), + new MissingGroupOptionError("err-group", optionNames2) + }; + + // Exercize system + var result = InvokeBuild( + new[] { "-v 10.42" }); + + // Verify outcome + ((NotParsed)result).Errors.Should().BeEquivalentTo(expectedResult); + } + [Theory] [InlineData("-v", "10.5", "--option1", "test1", "--option2", "test2")] [InlineData("-v", "10.5", "--option1", "test1")] From f67c1041437c988135d21ecfdec8a7faa6b98aad Mon Sep 17 00:00:00 2001 From: Vladislav Hadzhiyski Date: Sun, 2 Feb 2020 18:36:15 +0200 Subject: [PATCH 5/5] MissingGroupOptionError compare option names --- src/CommandLine/Error.cs | 3 ++- tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CommandLine/Error.cs b/src/CommandLine/Error.cs index c07bb2d1..b6e8a605 100644 --- a/src/CommandLine/Error.cs +++ b/src/CommandLine/Error.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Linq; namespace CommandLine { @@ -577,7 +578,7 @@ public bool Equals(MissingGroupOptionError other) return false; } - return Group.Equals(other.Group); + return Group.Equals(other.Group) && Names.SequenceEqual(other.Names); } } diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 1792fef6..643878fd 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -1127,7 +1127,7 @@ public void Options_In_Group_With_No_Values_Generates_MissingGroupOptionErrors() var expectedResult = new[] { new MissingGroupOptionError("err-group", optionNames1), - new MissingGroupOptionError("err-group", optionNames2) + new MissingGroupOptionError("err-group2", optionNames2) }; // Exercize system