diff --git a/src/CommandLine/Core/InstanceBuilder.cs b/src/CommandLine/Core/InstanceBuilder.cs index f48127b1..05c4056a 100644 --- a/src/CommandLine/Core/InstanceBuilder.cs +++ b/src/CommandLine/Core/InstanceBuilder.cs @@ -22,6 +22,7 @@ public static ParserResult Build( CultureInfo parsingCulture, bool autoHelp, bool autoVersion, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { return Build( @@ -34,6 +35,7 @@ public static ParserResult Build( autoHelp, autoVersion, false, + optionsParseMode, nonFatalErrors); } @@ -47,6 +49,7 @@ public static ParserResult Build( bool autoHelp, bool autoVersion, bool allowMultiInstance, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { var typeInfo = factory.MapValueOrDefault(f => f().GetType(), typeof(T)); @@ -137,7 +140,7 @@ public static ParserResult Build( var preprocessorErrors = ( argumentsList.Any() - ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer, autoHelp, autoVersion)) + ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer, autoHelp, autoVersion, optionsParseMode)) : Enumerable.Empty() ).Memoize(); diff --git a/src/CommandLine/Core/InstanceChooser.cs b/src/CommandLine/Core/InstanceChooser.cs index 72307bf2..02209e44 100644 --- a/src/CommandLine/Core/InstanceChooser.cs +++ b/src/CommandLine/Core/InstanceChooser.cs @@ -21,6 +21,7 @@ public static ParserResult Choose( CultureInfo parsingCulture, bool autoHelp, bool autoVersion, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { return Choose( @@ -33,6 +34,7 @@ public static ParserResult Choose( autoHelp, autoVersion, false, + optionsParseMode, nonFatalErrors); } @@ -46,6 +48,7 @@ public static ParserResult Choose( bool autoHelp, bool autoVersion, bool allowMultiInstance, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { var verbs = Verb.SelectFromTypes(types); @@ -62,8 +65,9 @@ ParserResult choose() var firstArg = arguments.First(); bool preprocCompare(string command) => - nameComparer.Equals(command, firstArg) || - nameComparer.Equals(string.Concat("--", command), firstArg); + nameComparer.Equals(command, firstArg) + || optionsParseMode != OptionsParseMode.SingleDashOnly && nameComparer.Equals(string.Concat("--", command), firstArg) + || optionsParseMode != OptionsParseMode.Default && nameComparer.Equals(string.Concat("-", command), firstArg); return (autoHelp && preprocCompare("help")) ? MakeNotParsed(types, @@ -71,13 +75,13 @@ bool preprocCompare(string command) => arguments.Skip(1).FirstOrDefault() ?? string.Empty, nameComparer)) : (autoVersion && preprocCompare("version")) ? MakeNotParsed(types, new VersionRequestedError()) - : MatchVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, allowMultiInstance, nonFatalErrors); + : MatchVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, allowMultiInstance, optionsParseMode, nonFatalErrors); } return arguments.Any() ? choose() : (defaultVerbCount == 1 - ? MatchDefaultVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, nonFatalErrors) + ? MatchDefaultVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, optionsParseMode, nonFatalErrors) : MakeNotParsed(types, new NoVerbSelectedError())); } @@ -91,6 +95,7 @@ private static ParserResult MatchDefaultVerb( CultureInfo parsingCulture, bool autoHelp, bool autoVersion, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { return !(defaultVerb is null) @@ -103,6 +108,7 @@ private static ParserResult MatchDefaultVerb( parsingCulture, autoHelp, autoVersion, + optionsParseMode, nonFatalErrors) : MakeNotParsed(verbs.Select(v => v.Item2), new BadVerbSelectedError(arguments.First())); } @@ -118,6 +124,7 @@ private static ParserResult MatchVerb( bool autoHelp, bool autoVersion, bool allowMultiInstance, + OptionsParseMode optionsParseMode, IEnumerable nonFatalErrors) { string firstArg = arguments.First(); @@ -129,7 +136,7 @@ private static ParserResult MatchVerb( if (verbUsed == default) { - return MatchDefaultVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, nonFatalErrors); + return MatchDefaultVerb(tokenizer, verbs, defaultVerb, arguments, nameComparer, ignoreValueCase, parsingCulture, autoHelp, autoVersion, optionsParseMode, nonFatalErrors); } return InstanceBuilder.Build( Maybe.Just>( @@ -141,7 +148,8 @@ private static ParserResult MatchVerb( parsingCulture, autoHelp, autoVersion, - allowMultiInstance, + allowMultiInstance, + optionsParseMode, nonFatalErrors); } diff --git a/src/CommandLine/Core/PreprocessorGuards.cs b/src/CommandLine/Core/PreprocessorGuards.cs index 8d6fb5be..3d8a7fac 100644 --- a/src/CommandLine/Core/PreprocessorGuards.cs +++ b/src/CommandLine/Core/PreprocessorGuards.cs @@ -9,30 +9,31 @@ namespace CommandLine.Core static class PreprocessorGuards { public static IEnumerable, IEnumerable>> - Lookup(StringComparer nameComparer, bool autoHelp, bool autoVersion) + Lookup(StringComparer nameComparer, bool autoHelp, bool autoVersion, OptionsParseMode optionsParseMode) { var list = new List, IEnumerable>>(); if (autoHelp) - list.Add(HelpCommand(nameComparer)); + list.Add(HelpCommand(nameComparer, optionsParseMode)); if (autoVersion) - list.Add(VersionCommand(nameComparer)); + list.Add(VersionCommand(nameComparer, optionsParseMode)); return list; } - - public static Func, IEnumerable> HelpCommand(StringComparer nameComparer) + public static Func, IEnumerable> HelpCommand(StringComparer nameComparer, OptionsParseMode optionsParseMode) { return arguments => - nameComparer.Equals("--help", arguments.First()) + optionsParseMode != OptionsParseMode.SingleDashOnly && nameComparer.Equals("--help", arguments.First()) + || optionsParseMode != OptionsParseMode.Default && nameComparer.Equals("-help", arguments.First()) ? new Error[] { new HelpRequestedError() } : Enumerable.Empty(); } - public static Func, IEnumerable> VersionCommand(StringComparer nameComparer) + public static Func, IEnumerable> VersionCommand(StringComparer nameComparer, OptionsParseMode optionsParseMode) { return arguments => - nameComparer.Equals("--version", arguments.First()) + optionsParseMode != OptionsParseMode.SingleDashOnly && nameComparer.Equals("--version", arguments.First()) + || optionsParseMode != OptionsParseMode.Default && nameComparer.Equals("-version", arguments.First()) ? new Error[] { new VersionRequestedError() } : Enumerable.Empty(); } diff --git a/src/CommandLine/Parser.cs b/src/CommandLine/Parser.cs index 2f0a1fe3..ca542917 100644 --- a/src/CommandLine/Parser.cs +++ b/src/CommandLine/Parser.cs @@ -102,6 +102,7 @@ public ParserResult ParseArguments(IEnumerable args) settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, + settings.OptionsParseMode, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } @@ -133,6 +134,7 @@ public ParserResult ParseArguments(Func factory, IEnumerable ar settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, + settings.OptionsParseMode, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } @@ -166,6 +168,7 @@ public ParserResult ParseArguments(IEnumerable args, params Type settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, + settings.OptionsParseMode, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 2f8d02b7..8bd3c830 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -19,7 +19,7 @@ namespace CommandLine.Tests.Unit.Core { public class InstanceBuilderTests { - private static ParserResult InvokeBuild(string[] arguments, bool autoHelp = true, bool autoVersion = true, bool multiInstance = false) + private static ParserResult InvokeBuild(string[] arguments, bool autoHelp = true, bool autoVersion = true, bool multiInstance = false, OptionsParseMode optionsParseMode = OptionsParseMode.Default) where T : new() { return InstanceBuilder.Build( @@ -32,6 +32,7 @@ private static ParserResult InvokeBuild(string[] arguments, bool autoHelp autoHelp, autoVersion, multiInstance, + optionsParseMode, Enumerable.Empty()); } @@ -47,6 +48,7 @@ private static ParserResult InvokeBuildEnumValuesCaseIgnore(string[] argum CultureInfo.InvariantCulture, true, true, + OptionsParseMode.Default, Enumerable.Empty()); } @@ -61,6 +63,7 @@ private static ParserResult InvokeBuildImmutable(string[] arguments) CultureInfo.InvariantCulture, true, true, + OptionsParseMode.Default, Enumerable.Empty()); } @@ -421,6 +424,7 @@ public void Double_dash_force_subsequent_arguments_as_values() CultureInfo.InvariantCulture, true, true, + OptionsParseMode.Default, Enumerable.Empty()); // Verify outcome @@ -1263,6 +1267,43 @@ public void Parse_int_sequence_with_multi_instance() ((Parsed)result).Value.IntSequence.Should().BeEquivalentTo(expected); } + + [Theory] + [InlineData("-help", OptionsParseMode.SingleDashOnly)] + [InlineData("-help", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("--help", OptionsParseMode.Default)] + [InlineData("--help", OptionsParseMode.SingleOrDoubleDash)] + public void Parse_Built_In_Help_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeBuild(new[] { argument }, optionsParseMode: optionsParseMode); + + result.Errors.Single().Should().BeOfType(); + } + + [Theory] + [InlineData("-version", OptionsParseMode.SingleDashOnly)] + [InlineData("-version", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("--version", OptionsParseMode.Default)] + [InlineData("--version", OptionsParseMode.SingleOrDoubleDash)] + public void Parse_Built_In_Version_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeBuild(new[] { argument }, optionsParseMode: optionsParseMode); + + result.Errors.Single().Should().BeOfType(); + } + + [Theory] + [InlineData("-help", OptionsParseMode.Default)] + [InlineData("--help", OptionsParseMode.SingleDashOnly)] + [InlineData("-version", OptionsParseMode.Default)] + [InlineData("--version", OptionsParseMode.SingleDashOnly)] + public void Parse_Invalid_Built_In_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeBuild(new[] { argument }, optionsParseMode: optionsParseMode); + + result.Errors.Should().NotBeOfType() + .And.Should().NotBeOfType(); + } #region custom types diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs index d5cb9a21..0518842f 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs @@ -16,7 +16,8 @@ public class InstanceChooserTests private static ParserResult InvokeChoose( IEnumerable types, IEnumerable arguments, - bool multiInstance = false) + bool multiInstance = false, + OptionsParseMode optionsParseMode = OptionsParseMode.Default) { return InstanceChooser.Choose( (args, optionSpecs) => Tokenizer.ConfigureTokenizer(StringComparer.Ordinal, false, false)(args, optionSpecs), @@ -28,6 +29,7 @@ private static ParserResult InvokeChoose( true, true, multiInstance, + optionsParseMode, Enumerable.Empty()); } @@ -183,5 +185,60 @@ public void Parse_sequence_verb_with_multi_instance_returns_verb_instance() Assert.IsType(((Parsed)result).Value); expected.Should().BeEquivalentTo(((Parsed)result).Value); } + + [Theory] + [InlineData("help", OptionsParseMode.Default)] + [InlineData("help", OptionsParseMode.SingleDashOnly)] + [InlineData("help", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("-help", OptionsParseMode.SingleDashOnly)] + [InlineData("-help", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("--help", OptionsParseMode.Default)] + [InlineData("--help", OptionsParseMode.SingleOrDoubleDash)] + public void Parse_Built_In_Help_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeChoose( + Type.EmptyTypes, + new[] { argument }, + true, + optionsParseMode); + + result.Errors.Single().Should().BeOfType(); + } + + [Theory] + [InlineData("version", OptionsParseMode.Default)] + [InlineData("version", OptionsParseMode.SingleDashOnly)] + [InlineData("version", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("-version", OptionsParseMode.SingleDashOnly)] + [InlineData("-version", OptionsParseMode.SingleOrDoubleDash)] + [InlineData("--version", OptionsParseMode.Default)] + [InlineData("--version", OptionsParseMode.SingleOrDoubleDash)] + public void Parse_Built_In_Version_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeChoose( + Type.EmptyTypes, + new[] { argument }, + true, + optionsParseMode); + + result.Errors.Single().Should().BeOfType(); + } + + [Theory] + [InlineData("-help", OptionsParseMode.Default)] + [InlineData("--help", OptionsParseMode.SingleDashOnly)] + [InlineData("-version", OptionsParseMode.Default)] + [InlineData("--version", OptionsParseMode.SingleDashOnly)] + public void Parse_Invalid_Built_In_Argument(string argument, OptionsParseMode optionsParseMode) + { + var result = InvokeChoose( + Type.EmptyTypes, + new[] { argument }, + true, + optionsParseMode); + + result.Errors.Single().Should().NotBeOfType() + .And.Should().NotBeOfType(); + } } }