Add switch to enable expected and unexpected arguments in any order (dotnet/extensions#2210)
- unblocks work on aspnet/AspNetCoredotnet/extensions#4923
- arguments for inside and outside men of service reference doc gen tool are mixed by default
- users may add either argument type to the end of the outside man's command line
- e.g. "command --unexpected unexpectedValue --expected" can now set the "expected" option
- only "--unexpected" and "unexpectedValue" are added to RemainingArguments in that case
- default behaviour of the command-line parser is unchanged to avoid breaking existing applications
- new switch is supported only when calling `CommandLineApplication` constructor for top-level commands
- `dotnet-getdocument` (the outside man) has no (sub)commands and expanding scope would increase churn
nits: take VS suggestions in changed files\n\nCommit migrated from e4433979b6
This commit is contained in:
parent
d46d569b81
commit
1153f0d1de
|
|
@ -13,14 +13,23 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
{
|
||||
internal class CommandLineApplication
|
||||
{
|
||||
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
|
||||
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
|
||||
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
|
||||
// Indicates whether the parser should throw an exception when it runs into an unexpected argument. If this is
|
||||
// set to true (the default), the parser will throw on the first unexpected argument. Otherwise, all unexpected
|
||||
// arguments (including the first) are added to RemainingArguments.
|
||||
private readonly bool _throwOnUnexpectedArg;
|
||||
|
||||
public CommandLineApplication(bool throwOnUnexpectedArg = true)
|
||||
// Indicates whether the parser should check remaining arguments for command or option matches after
|
||||
// encountering an unexpected argument. Ignored if _throwOnUnexpectedArg is true (the default). If
|
||||
// _throwOnUnexpectedArg and this are both false, the first unexpected argument and all remaining arguments are
|
||||
// added to RemainingArguments. If _throwOnUnexpectedArg is false and this is true, only unexpected arguments
|
||||
// are added to RemainingArguments -- allowing a mix of expected and unexpected arguments, commands and
|
||||
// options.
|
||||
private readonly bool _continueAfterUnexpectedArg;
|
||||
|
||||
public CommandLineApplication(bool throwOnUnexpectedArg = true, bool continueAfterUnexpectedArg = false)
|
||||
{
|
||||
_throwOnUnexpectedArg = throwOnUnexpectedArg;
|
||||
_continueAfterUnexpectedArg = continueAfterUnexpectedArg;
|
||||
Options = new List<CommandOption>();
|
||||
Arguments = new List<CommandArgument>();
|
||||
Commands = new List<CommandLineApplication>();
|
||||
|
|
@ -145,6 +154,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
{
|
||||
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
|
||||
}
|
||||
|
||||
if (longOption != null)
|
||||
{
|
||||
processed = true;
|
||||
|
|
@ -153,13 +163,27 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
|
||||
if (option == null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(longOptionName) && !command._throwOnUnexpectedArg && AllowArgumentSeparator)
|
||||
var ignoreContinueAfterUnexpectedArg = false;
|
||||
if (string.IsNullOrEmpty(longOptionName) &&
|
||||
!command._throwOnUnexpectedArg &&
|
||||
AllowArgumentSeparator)
|
||||
{
|
||||
// skip over the '--' argument separator
|
||||
// Skip over the '--' argument separator then consume all remaining arguments. All
|
||||
// remaining arguments are unconditionally stored for further use.
|
||||
index++;
|
||||
ignoreContinueAfterUnexpectedArg = true;
|
||||
}
|
||||
|
||||
if (HandleUnexpectedArg(
|
||||
command,
|
||||
args,
|
||||
index,
|
||||
argTypeName: "option",
|
||||
ignoreContinueAfterUnexpectedArg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +215,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
option = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (shortOption != null)
|
||||
{
|
||||
processed = true;
|
||||
|
|
@ -204,7 +229,11 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
|
||||
if (option == null)
|
||||
{
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
||||
if (HandleUnexpectedArg(command, args, index, argTypeName: "option"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -268,6 +297,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!processed)
|
||||
{
|
||||
if (arguments == null)
|
||||
|
|
@ -280,9 +310,14 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
arguments.Current.Values.Add(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processed)
|
||||
{
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
|
||||
if (HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -490,17 +525,29 @@ namespace Microsoft.Extensions.CommandLineUtils
|
|||
Out.WriteLine();
|
||||
}
|
||||
|
||||
private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
|
||||
private bool HandleUnexpectedArg(
|
||||
CommandLineApplication command,
|
||||
string[] args,
|
||||
int index,
|
||||
string argTypeName,
|
||||
bool ignoreContinueAfterUnexpectedArg = false)
|
||||
{
|
||||
if (command._throwOnUnexpectedArg)
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
|
||||
}
|
||||
else if (_continueAfterUnexpectedArg && !ignoreContinueAfterUnexpectedArg)
|
||||
{
|
||||
// Store argument for further use.
|
||||
command.RemainingArguments.Add(args[index]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All remaining arguments are stored for further use
|
||||
// Store all remaining arguments for later use.
|
||||
command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -73,6 +72,30 @@ namespace Microsoft.Extensions.Internal
|
|||
Assert.Contains("three", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtraArgumentAddedToRemaining()
|
||||
{
|
||||
CommandArgument first = null;
|
||||
CommandArgument second = null;
|
||||
|
||||
var app = new CommandLineApplication();
|
||||
|
||||
var testCommand = app.Command("test", c =>
|
||||
{
|
||||
first = c.Argument("first", "First argument");
|
||||
second = c.Argument("second", "Second argument");
|
||||
c.OnExecute(() => 0);
|
||||
},
|
||||
throwOnUnexpectedArg: false);
|
||||
|
||||
app.Execute("test", "one", "two", "three");
|
||||
|
||||
Assert.Equal("one", first.Value);
|
||||
Assert.Equal("two", second.Value);
|
||||
var remaining = Assert.Single(testCommand.RemainingArguments);
|
||||
Assert.Equal("three", remaining);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnknownCommandCausesException()
|
||||
{
|
||||
|
|
@ -257,6 +280,145 @@ namespace Microsoft.Extensions.Internal
|
|||
Assert.Equal(unexpectedArg, arg);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowArgumentBeforeNoValueOption()
|
||||
{
|
||||
var app = new CommandLineApplication();
|
||||
var argument = app.Argument("first", "first argument");
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
app.Execute("one", "--first");
|
||||
|
||||
Assert.Equal("one", argument.Value);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowArgumentAfterNoValueOption()
|
||||
{
|
||||
var app = new CommandLineApplication();
|
||||
var argument = app.Argument("first", "first argument");
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
app.Execute("--first", "one");
|
||||
|
||||
Assert.Equal("one", argument.Value);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowArgumentBeforeSingleValueOption()
|
||||
{
|
||||
var app = new CommandLineApplication();
|
||||
var argument = app.Argument("first", "first argument");
|
||||
var option = app.Option("--first <value>", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
app.Execute("one", "--first", "two");
|
||||
|
||||
Assert.Equal("one", argument.Value);
|
||||
Assert.Equal("two", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowArgumentAfterSingleValueOption()
|
||||
{
|
||||
var app = new CommandLineApplication();
|
||||
var argument = app.Argument("first", "first argument");
|
||||
var option = app.Option("--first <value>", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
app.Execute("--first", "one", "two");
|
||||
|
||||
Assert.Equal("two", argument.Value);
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentBeforeNoValueOption_Default()
|
||||
{
|
||||
var arguments = new[] { "UnexpectedArg", "--first" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
Assert.False(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentBeforeNoValueOption_Continue()
|
||||
{
|
||||
var unexpectedArg = "UnexpectedArg";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedArg, "--first");
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedArg, arg);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentAfterNoValueOption()
|
||||
{
|
||||
var unexpectedArg = "UnexpectedArg";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", unexpectedArg);
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedArg, arg);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentBeforeSingleValueOption_Default()
|
||||
{
|
||||
var arguments = new[] { "UnexpectedArg", "--first", "one" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentBeforeSingleValueOption_Continue()
|
||||
{
|
||||
var unexpectedArg = "UnexpectedArg";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedArg, "--first", "one");
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedArg, arg);
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedArgumentAfterSingleValueOption()
|
||||
{
|
||||
var unexpectedArg = "UnexpectedArg";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", "one", unexpectedArg);
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedArg, arg);
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowsExceptionOnUnexpectedLongOptionByDefault()
|
||||
{
|
||||
|
|
@ -290,6 +452,183 @@ namespace Microsoft.Extensions.Internal
|
|||
Assert.Equal(unexpectedOption, arg);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionBeforeNoValueOption_Default()
|
||||
{
|
||||
var arguments = new[] { "--unexpected", "--first" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionBeforeNoValueOption_Continue()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedOption, "--first");
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, arg);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionAfterNoValueOption()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", unexpectedOption);
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, arg);
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionBeforeSingleValueOption_Default()
|
||||
{
|
||||
var arguments = new[] { "--unexpected", "--first", "one" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionBeforeSingleValueOption_Continue()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedOption, "--first", "one");
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, arg);
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionAfterSingleValueOption()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", "one", unexpectedOption);
|
||||
|
||||
var arg = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, arg);
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueBeforeNoValueOption_Default()
|
||||
{
|
||||
var arguments = new[] { "--unexpected", "value", "--first" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueBeforeNoValueOption_Continue()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var unexpectedValue = "value";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedOption, unexpectedValue, "--first");
|
||||
|
||||
Assert.Equal(new[] { unexpectedOption, unexpectedValue }, app.RemainingArguments.ToArray());
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueAfterNoValueOption()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var unexpectedValue = "value";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.NoValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", unexpectedOption, unexpectedValue);
|
||||
|
||||
Assert.Equal(new[] { unexpectedOption, unexpectedValue }, app.RemainingArguments.ToArray());
|
||||
Assert.True(option.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueBeforeSingleValueOption_Default()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var unexpectedValue = "value";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedOption, unexpectedValue, "--first", "one");
|
||||
|
||||
Assert.Equal(
|
||||
new[] { unexpectedOption, unexpectedValue, "--first", "one" },
|
||||
app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueBeforeSingleValueOption_Continue()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var unexpectedValue = "value";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute(unexpectedOption, unexpectedValue, "--first", "one");
|
||||
|
||||
Assert.Equal(
|
||||
new[] { unexpectedOption, unexpectedValue },
|
||||
app.RemainingArguments.ToArray());
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedLongOptionWithValueAfterSingleValueOption()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var unexpectedValue = "value";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var option = app.Option("--first", "first option", CommandOptionType.SingleValue);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("--first", "one", unexpectedOption, unexpectedValue);
|
||||
|
||||
Assert.Equal(new[] { unexpectedOption, unexpectedValue }, app.RemainingArguments.ToArray());
|
||||
Assert.Equal("one", option.Value());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowsExceptionOnUnexpectedShortOptionByDefault()
|
||||
{
|
||||
|
|
@ -373,13 +712,35 @@ namespace Microsoft.Extensions.Internal
|
|||
Assert.Equal($"Unrecognized option '{unexpectedOption}'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedOptionBeforeSubcommand()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication();
|
||||
|
||||
CommandLineApplication subCmd = null;
|
||||
var testCmd = app.Command("k", c =>
|
||||
{
|
||||
subCmd = c.Command("run", _ => { });
|
||||
c.OnExecute(() => 0);
|
||||
},
|
||||
throwOnUnexpectedArg: false);
|
||||
|
||||
// (does not throw)
|
||||
app.Execute("k", unexpectedOption, "run");
|
||||
|
||||
Assert.Empty(app.RemainingArguments);
|
||||
Assert.Equal(new[] { unexpectedOption, "run" }, testCmd.RemainingArguments.ToArray());
|
||||
Assert.Empty(subCmd.RemainingArguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedOptionAfterSubcommand()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
CommandLineApplication subCmd = null;
|
||||
var app = new CommandLineApplication();
|
||||
|
||||
CommandLineApplication subCmd = null;
|
||||
var testCmd = app.Command("k", c =>
|
||||
{
|
||||
subCmd = c.Command("run", _ => { }, throwOnUnexpectedArg: false);
|
||||
|
|
@ -388,11 +749,44 @@ namespace Microsoft.Extensions.Internal
|
|||
|
||||
// (does not throw)
|
||||
app.Execute("k", "run", unexpectedOption);
|
||||
|
||||
Assert.Empty(app.RemainingArguments);
|
||||
Assert.Empty(testCmd.RemainingArguments);
|
||||
var arg = Assert.Single(subCmd.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, arg);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedOptionBeforeValidCommand_Default()
|
||||
{
|
||||
var arguments = new[] { "--unexpected", "run" };
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var commandRan = false;
|
||||
app.Command("run", c => c.OnExecute(() => { commandRan = true; return 0; }));
|
||||
app.OnExecute(() => 0);
|
||||
|
||||
app.Execute(arguments);
|
||||
|
||||
Assert.False(commandRan);
|
||||
Assert.Equal(arguments, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowNoThrowBehaviorOnUnexpectedOptionBeforeValidCommand_Continue()
|
||||
{
|
||||
var unexpectedOption = "--unexpected";
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var commandRan = false;
|
||||
app.Command("run", c => c.OnExecute(() => { commandRan = true; return 0; }));
|
||||
app.OnExecute(() => 0);
|
||||
|
||||
app.Execute(unexpectedOption, "run");
|
||||
|
||||
Assert.True(commandRan);
|
||||
var remaining = Assert.Single(app.RemainingArguments);
|
||||
Assert.Equal(unexpectedOption, remaining);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OptionsCanBeInherited()
|
||||
{
|
||||
|
|
@ -530,6 +924,91 @@ namespace Microsoft.Extensions.Internal
|
|||
Assert.Equal(expectedRemaining, app.RemainingArguments.ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[0], new string[0], null, false)]
|
||||
[InlineData(new[] { "--" }, new[] { "--" }, null, false)]
|
||||
[InlineData(new[] { "-t", "val" }, new string[0], "val", false)]
|
||||
[InlineData(new[] { "-t", "val", "--" }, new[] { "--" }, "val", false)]
|
||||
[InlineData(new[] { "--top", "val", "--", "a" }, new[] { "--", "a" }, "val", false)]
|
||||
[InlineData(new[] { "-t", "val", "--", "a", "--", "b" }, new[] { "--", "a", "--", "b" }, "val", false)]
|
||||
[InlineData(new[] { "--help", "--" }, new string[0], null, true)]
|
||||
[InlineData(new[] { "--version", "--" }, new string[0], null, true)]
|
||||
public void ArgumentSeparator_TreatedAsUexpected(
|
||||
string[] input,
|
||||
string[] expectedRemaining,
|
||||
string topLevelValue,
|
||||
bool isShowingInformation)
|
||||
{
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var optHelp = app.HelpOption("--help");
|
||||
var optVersion = app.VersionOption("--version", "1", "1.0");
|
||||
var optTop = app.Option("-t|--top <TOP>", "arg for command", CommandOptionType.SingleValue);
|
||||
|
||||
app.Execute(input);
|
||||
|
||||
Assert.Equal(topLevelValue, optTop.Value());
|
||||
Assert.Equal(expectedRemaining, app.RemainingArguments.ToArray());
|
||||
Assert.Equal(isShowingInformation, app.IsShowingInformation);
|
||||
|
||||
// Help and Version options never get values; parsing ends when encountered.
|
||||
Assert.False(optHelp.HasValue());
|
||||
Assert.False(optVersion.HasValue());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new[] { "--", "a", "--top", "val" }, new[] { "--", "a", "--top", "val" }, null, false)]
|
||||
[InlineData(new[] { "--", "--help" }, new[] { "--", "--help" }, null, false)]
|
||||
[InlineData(new[] { "--", "--version" }, new[] { "--", "--version" }, null, false)]
|
||||
[InlineData(new[] { "unexpected", "--", "--version" }, new[] { "unexpected", "--", "--version" }, null, false)]
|
||||
public void ArgumentSeparator_TreatedAsUexpected_Default(
|
||||
string[] input,
|
||||
string[] expectedRemaining,
|
||||
string topLevelValue,
|
||||
bool isShowingInformation)
|
||||
{
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false);
|
||||
var optHelp = app.HelpOption("--help");
|
||||
var optVersion = app.VersionOption("--version", "1", "1.0");
|
||||
var optTop = app.Option("-t|--top <TOP>", "arg for command", CommandOptionType.SingleValue);
|
||||
|
||||
app.Execute(input);
|
||||
|
||||
Assert.Equal(topLevelValue, optTop.Value());
|
||||
Assert.Equal(expectedRemaining, app.RemainingArguments.ToArray());
|
||||
Assert.Equal(isShowingInformation, app.IsShowingInformation);
|
||||
|
||||
// Help and Version options never get values; parsing ends when encountered.
|
||||
Assert.False(optHelp.HasValue());
|
||||
Assert.False(optVersion.HasValue());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new[] { "--", "a", "--top", "val" }, new[] { "--", "a" }, "val", false)]
|
||||
[InlineData(new[] { "--", "--help" }, new[] { "--" }, null, true)]
|
||||
[InlineData(new[] { "--", "--version" }, new[] { "--" }, null, true)]
|
||||
[InlineData(new[] { "unexpected", "--", "--version" }, new[] { "unexpected", "--" }, null, true)]
|
||||
public void ArgumentSeparator_TreatedAsUexpected_Continue(
|
||||
string[] input,
|
||||
string[] expectedRemaining,
|
||||
string topLevelValue,
|
||||
bool isShowingInformation)
|
||||
{
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false, continueAfterUnexpectedArg: true);
|
||||
var optHelp = app.HelpOption("--help");
|
||||
var optVersion = app.VersionOption("--version", "1", "1.0");
|
||||
var optTop = app.Option("-t|--top <TOP>", "arg for command", CommandOptionType.SingleValue);
|
||||
|
||||
app.Execute(input);
|
||||
|
||||
Assert.Equal(topLevelValue, optTop.Value());
|
||||
Assert.Equal(expectedRemaining, app.RemainingArguments.ToArray());
|
||||
Assert.Equal(isShowingInformation, app.IsShowingInformation);
|
||||
|
||||
// Help and Version options never get values; parsing ends when encountered.
|
||||
Assert.False(optHelp.HasValue());
|
||||
Assert.False(optVersion.HasValue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HelpTextIgnoresHiddenItems()
|
||||
{
|
||||
|
|
@ -607,20 +1086,18 @@ Examples:
|
|||
[InlineData(new[] { "-h", "-f" }, "some flag")]
|
||||
public void HelpAndVersionOptionStopProcessing(string[] input, string expectedOutData)
|
||||
{
|
||||
using (var outWriter = new StringWriter())
|
||||
{
|
||||
var app = new CommandLineApplication { Out = outWriter };
|
||||
app.HelpOption("-h --help");
|
||||
app.VersionOption("-V --version", "1", "1.0");
|
||||
var optFlag = app.Option("-f |--flag", "some flag", CommandOptionType.NoValue);
|
||||
using var outWriter = new StringWriter();
|
||||
var app = new CommandLineApplication { Out = outWriter };
|
||||
app.HelpOption("-h --help");
|
||||
app.VersionOption("-V --version", "1", "1.0");
|
||||
var optFlag = app.Option("-f |--flag", "some flag", CommandOptionType.NoValue);
|
||||
|
||||
app.Execute(input);
|
||||
app.Execute(input);
|
||||
|
||||
outWriter.Flush();
|
||||
var outData = outWriter.ToString();
|
||||
Assert.Contains(expectedOutData, outData);
|
||||
Assert.False(optFlag.HasValue());
|
||||
}
|
||||
outWriter.Flush();
|
||||
var outData = outWriter.ToString();
|
||||
Assert.Contains(expectedOutData, outData);
|
||||
Assert.False(optFlag.HasValue());
|
||||
}
|
||||
|
||||
// disable inaccurate analyzer error https://github.com/xunit/xunit/issues/1274
|
||||
|
|
|
|||
Loading…
Reference in New Issue