Merge pull request dotnet/extensions#2219 from dotnet-maestro-bot/merge/release/3.0-to-master
[automated] Merge branch 'release/3.0' => 'master'\n\nCommit migrated from 14efea27d2
This commit is contained in:
commit
116144358b
|
|
@ -13,14 +13,23 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
{
|
{
|
||||||
internal class CommandLineApplication
|
internal class CommandLineApplication
|
||||||
{
|
{
|
||||||
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
|
// Indicates whether the parser should throw an exception when it runs into an unexpected argument. If this is
|
||||||
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
|
// set to true (the default), the parser will throw on the first unexpected argument. Otherwise, all unexpected
|
||||||
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
|
// arguments (including the first) are added to RemainingArguments.
|
||||||
private readonly bool _throwOnUnexpectedArg;
|
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;
|
_throwOnUnexpectedArg = throwOnUnexpectedArg;
|
||||||
|
_continueAfterUnexpectedArg = continueAfterUnexpectedArg;
|
||||||
Options = new List<CommandOption>();
|
Options = new List<CommandOption>();
|
||||||
Arguments = new List<CommandArgument>();
|
Arguments = new List<CommandArgument>();
|
||||||
Commands = new List<CommandLineApplication>();
|
Commands = new List<CommandLineApplication>();
|
||||||
|
|
@ -145,6 +154,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
{
|
{
|
||||||
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
|
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (longOption != null)
|
if (longOption != null)
|
||||||
{
|
{
|
||||||
processed = true;
|
processed = true;
|
||||||
|
|
@ -153,13 +163,27 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
|
|
||||||
if (option == null)
|
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++;
|
index++;
|
||||||
|
ignoreContinueAfterUnexpectedArg = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HandleUnexpectedArg(
|
||||||
|
command,
|
||||||
|
args,
|
||||||
|
index,
|
||||||
|
argTypeName: "option",
|
||||||
|
ignoreContinueAfterUnexpectedArg))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +215,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
option = null;
|
option = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shortOption != null)
|
if (shortOption != null)
|
||||||
{
|
{
|
||||||
processed = true;
|
processed = true;
|
||||||
|
|
@ -204,7 +229,11 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
|
|
||||||
if (option == null)
|
if (option == null)
|
||||||
{
|
{
|
||||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
if (HandleUnexpectedArg(command, args, index, argTypeName: "option"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,6 +297,7 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!processed)
|
if (!processed)
|
||||||
{
|
{
|
||||||
if (arguments == null)
|
if (arguments == null)
|
||||||
|
|
@ -280,9 +310,14 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
arguments.Current.Values.Add(arg);
|
arguments.Current.Values.Add(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!processed)
|
if (!processed)
|
||||||
{
|
{
|
||||||
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
|
if (HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -490,17 +525,29 @@ namespace Microsoft.Extensions.CommandLineUtils
|
||||||
Out.WriteLine();
|
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)
|
if (command._throwOnUnexpectedArg)
|
||||||
{
|
{
|
||||||
command.ShowHint();
|
command.ShowHint();
|
||||||
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
|
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
|
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));
|
command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Extensions.CommandLineUtils;
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -73,6 +72,30 @@ namespace Microsoft.Extensions.Internal
|
||||||
Assert.Contains("three", ex.Message);
|
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]
|
[Fact]
|
||||||
public void UnknownCommandCausesException()
|
public void UnknownCommandCausesException()
|
||||||
{
|
{
|
||||||
|
|
@ -257,6 +280,145 @@ namespace Microsoft.Extensions.Internal
|
||||||
Assert.Equal(unexpectedArg, arg);
|
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]
|
[Fact]
|
||||||
public void ThrowsExceptionOnUnexpectedLongOptionByDefault()
|
public void ThrowsExceptionOnUnexpectedLongOptionByDefault()
|
||||||
{
|
{
|
||||||
|
|
@ -290,6 +452,183 @@ namespace Microsoft.Extensions.Internal
|
||||||
Assert.Equal(unexpectedOption, arg);
|
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]
|
[Fact]
|
||||||
public void ThrowsExceptionOnUnexpectedShortOptionByDefault()
|
public void ThrowsExceptionOnUnexpectedShortOptionByDefault()
|
||||||
{
|
{
|
||||||
|
|
@ -373,13 +712,35 @@ namespace Microsoft.Extensions.Internal
|
||||||
Assert.Equal($"Unrecognized option '{unexpectedOption}'", exception.Message);
|
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]
|
[Fact]
|
||||||
public void AllowNoThrowBehaviorOnUnexpectedOptionAfterSubcommand()
|
public void AllowNoThrowBehaviorOnUnexpectedOptionAfterSubcommand()
|
||||||
{
|
{
|
||||||
var unexpectedOption = "--unexpected";
|
var unexpectedOption = "--unexpected";
|
||||||
CommandLineApplication subCmd = null;
|
|
||||||
var app = new CommandLineApplication();
|
var app = new CommandLineApplication();
|
||||||
|
|
||||||
|
CommandLineApplication subCmd = null;
|
||||||
var testCmd = app.Command("k", c =>
|
var testCmd = app.Command("k", c =>
|
||||||
{
|
{
|
||||||
subCmd = c.Command("run", _ => { }, throwOnUnexpectedArg: false);
|
subCmd = c.Command("run", _ => { }, throwOnUnexpectedArg: false);
|
||||||
|
|
@ -388,11 +749,44 @@ namespace Microsoft.Extensions.Internal
|
||||||
|
|
||||||
// (does not throw)
|
// (does not throw)
|
||||||
app.Execute("k", "run", unexpectedOption);
|
app.Execute("k", "run", unexpectedOption);
|
||||||
|
|
||||||
|
Assert.Empty(app.RemainingArguments);
|
||||||
Assert.Empty(testCmd.RemainingArguments);
|
Assert.Empty(testCmd.RemainingArguments);
|
||||||
var arg = Assert.Single(subCmd.RemainingArguments);
|
var arg = Assert.Single(subCmd.RemainingArguments);
|
||||||
Assert.Equal(unexpectedOption, arg);
|
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]
|
[Fact]
|
||||||
public void OptionsCanBeInherited()
|
public void OptionsCanBeInherited()
|
||||||
{
|
{
|
||||||
|
|
@ -530,6 +924,91 @@ namespace Microsoft.Extensions.Internal
|
||||||
Assert.Equal(expectedRemaining, app.RemainingArguments.ToArray());
|
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]
|
[Fact]
|
||||||
public void HelpTextIgnoresHiddenItems()
|
public void HelpTextIgnoresHiddenItems()
|
||||||
{
|
{
|
||||||
|
|
@ -607,20 +1086,18 @@ Examples:
|
||||||
[InlineData(new[] { "-h", "-f" }, "some flag")]
|
[InlineData(new[] { "-h", "-f" }, "some flag")]
|
||||||
public void HelpAndVersionOptionStopProcessing(string[] input, string expectedOutData)
|
public void HelpAndVersionOptionStopProcessing(string[] input, string expectedOutData)
|
||||||
{
|
{
|
||||||
using (var outWriter = new StringWriter())
|
using var outWriter = new StringWriter();
|
||||||
{
|
var app = new CommandLineApplication { Out = outWriter };
|
||||||
var app = new CommandLineApplication { Out = outWriter };
|
app.HelpOption("-h --help");
|
||||||
app.HelpOption("-h --help");
|
app.VersionOption("-V --version", "1", "1.0");
|
||||||
app.VersionOption("-V --version", "1", "1.0");
|
var optFlag = app.Option("-f |--flag", "some flag", CommandOptionType.NoValue);
|
||||||
var optFlag = app.Option("-f |--flag", "some flag", CommandOptionType.NoValue);
|
|
||||||
|
|
||||||
app.Execute(input);
|
app.Execute(input);
|
||||||
|
|
||||||
outWriter.Flush();
|
outWriter.Flush();
|
||||||
var outData = outWriter.ToString();
|
var outData = outWriter.ToString();
|
||||||
Assert.Contains(expectedOutData, outData);
|
Assert.Contains(expectedOutData, outData);
|
||||||
Assert.False(optFlag.HasValue());
|
Assert.False(optFlag.HasValue());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable inaccurate analyzer error https://github.com/xunit/xunit/issues/1274
|
// disable inaccurate analyzer error https://github.com/xunit/xunit/issues/1274
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue