+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Microsoft.Extensions.CommandLineUtils
-{
- internal class CommandLineApplication
- {
- // 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;
-
- // 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;
-
- private readonly bool _treatUnmatchedOptionsAsArguments;
-
- public CommandLineApplication(bool throwOnUnexpectedArg = true, bool continueAfterUnexpectedArg = false, bool treatUnmatchedOptionsAsArguments = false)
- {
- _throwOnUnexpectedArg = throwOnUnexpectedArg;
- _continueAfterUnexpectedArg = continueAfterUnexpectedArg;
- _treatUnmatchedOptionsAsArguments = treatUnmatchedOptionsAsArguments;
- Options = new List<CommandOption>();
- Arguments = new List<CommandArgument>();
- Commands = new List<CommandLineApplication>();
- RemainingArguments = new List<string>();
- Invoke = () => 0;
- }
-
- public CommandLineApplication Parent { get; set; }
- public string Name { get; set; }
- public string FullName { get; set; }
- public string Syntax { get; set; }
- public string Description { get; set; }
- public bool ShowInHelpText { get; set; } = true;
- public string ExtendedHelpText { get; set; }
- public readonly List<CommandOption> Options;
- public CommandOption OptionHelp { get; private set; }
- public CommandOption OptionVersion { get; private set; }
- public readonly List<CommandArgument> Arguments;
- public readonly List<string> RemainingArguments;
- public bool IsShowingInformation { get; protected set; } // Is showing help or version?
- public Func<int> Invoke { get; set; }
- public Func<string> LongVersionGetter { get; set; }
- public Func<string> ShortVersionGetter { get; set; }
- public readonly List<CommandLineApplication> Commands;
- public bool AllowArgumentSeparator { get; set; }
- public TextWriter Out { get; set; } = Console.Out;
- public TextWriter Error { get; set; } = Console.Error;
-
- public IEnumerable<CommandOption> GetOptions()
- {
- var expr = Options.AsEnumerable();
- var rootNode = this;
- while (rootNode.Parent != null)
- {
- rootNode = rootNode.Parent;
- expr = expr.Concat(rootNode.Options.Where(o => o.Inherited));
- }
-
- return expr;
- }
-
- public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
- bool throwOnUnexpectedArg = true)
- {
- var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
- Commands.Add(command);
- configuration(command);
- return command;
- }
-
- public CommandOption Option(string template, string description, CommandOptionType optionType)
- => Option(template, description, optionType, _ => { }, inherited: false);
-
- public CommandOption Option(string template, string description, CommandOptionType optionType, bool inherited)
- => Option(template, description, optionType, _ => { }, inherited);
-
- public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
- => Option(template, description, optionType, configuration, inherited: false);
-
- public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration, bool inherited)
- {
- var option = new CommandOption(template, optionType)
- {
- Description = description,
- Inherited = inherited
- };
- Options.Add(option);
- configuration(option);
- return option;
- }
-
- public CommandArgument Argument(string name, string description, bool multipleValues = false)
- {
- return Argument(name, description, _ => { }, multipleValues);
- }
-
- public CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
- {
- var lastArg = Arguments.LastOrDefault();
- if (lastArg != null && lastArg.MultipleValues)
- {
- var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.",
- lastArg.Name);
- throw new InvalidOperationException(message);
- }
-
- var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
- Arguments.Add(argument);
- configuration(argument);
- return argument;
- }
-
- public void OnExecute(Func<int> invoke)
- {
- Invoke = invoke;
- }
-
- public void OnExecute(Func<Task<int>> invoke)
- {
- Invoke = () => invoke().Result;
- }
- public int Execute(params string[] args)
- {
- CommandLineApplication command = this;
- CommandOption option = null;
- IEnumerator<CommandArgument> arguments = null;
- var argumentsAssigned = false;
-
- for (var index = 0; index < args.Length; index++)
- {
- var arg = args[index];
- var processed = false;
- if (!processed && option == null)
- {
- string[] longOption = null;
- string[] shortOption = null;
-
- if (arg.StartsWith("--"))
- {
- longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2);
- }
- else if (arg.StartsWith("-"))
- {
- shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
- }
-
- if (longOption != null)
- {
- processed = true;
- var longOptionName = longOption[0];
- option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.LongName, longOptionName, StringComparison.Ordinal));
-
- if (option == null && _treatUnmatchedOptionsAsArguments)
- {
- if (arguments == null)
- {
- arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
- }
- if (arguments.MoveNext())
- {
- processed = true;
- arguments.Current.Values.Add(arg);
- argumentsAssigned = true;
- continue;
- }
- //else
- //{
- // argumentsAssigned = false;
- //}
- }
-
- if (option == null)
- {
- var ignoreContinueAfterUnexpectedArg = false;
- if (string.IsNullOrEmpty(longOptionName) &&
- !command._throwOnUnexpectedArg &&
- AllowArgumentSeparator)
- {
- // 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;
- }
-
- break;
- }
-
- // If we find a help/version option, show information and stop parsing
- if (command.OptionHelp == option)
- {
- command.ShowHelp();
- return 0;
- }
- else if (command.OptionVersion == option)
- {
- command.ShowVersion();
- return 0;
- }
-
- if (longOption.Length == 2)
- {
- if (!option.TryParse(longOption[1]))
- {
- command.ShowHint();
- throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'");
- }
- option = null;
- }
- else if (option.OptionType == CommandOptionType.NoValue)
- {
- // No value is needed for this option
- option.TryParse(null);
- option = null;
- }
- }
-
- if (shortOption != null)
- {
- processed = true;
- option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal));
-
- if (option == null && _treatUnmatchedOptionsAsArguments)
- {
- if (arguments == null)
- {
- arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
- }
- if (arguments.MoveNext())
- {
- processed = true;
- arguments.Current.Values.Add(arg);
- argumentsAssigned = true;
- continue;
- }
- //else
- //{
- // argumentsAssigned = false;
- //}
- }
-
- // If not a short option, try symbol option
- if (option == null)
- {
- option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal));
- }
-
- if (option == null)
- {
- if (HandleUnexpectedArg(command, args, index, argTypeName: "option"))
- {
- continue;
- }
-
- break;
- }
-
- // If we find a help/version option, show information and stop parsing
- if (command.OptionHelp == option)
- {
- command.ShowHelp();
- return 0;
- }
- else if (command.OptionVersion == option)
- {
- command.ShowVersion();
- return 0;
- }
-
- if (shortOption.Length == 2)
- {
- if (!option.TryParse(shortOption[1]))
- {
- command.ShowHint();
- throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'");
- }
- option = null;
- }
- else if (option.OptionType == CommandOptionType.NoValue)
- {
- // No value is needed for this option
- option.TryParse(null);
- option = null;
- }
- }
- }
-
- if (!processed && option != null)
- {
- processed = true;
- if (!option.TryParse(arg))
- {
- command.ShowHint();
- throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'");
- }
- option = null;
- }
-
- if (!processed && !argumentsAssigned)
- {
- var currentCommand = command;
- foreach (var subcommand in command.Commands)
- {
- if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
- {
- processed = true;
- command = subcommand;
- break;
- }
- }
-
- // If we detect a subcommand
- if (command != currentCommand)
- {
- processed = true;
- }
- }
-
- if (!processed)
- {
- if (arguments == null)
- {
- arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
- }
- if (arguments.MoveNext())
- {
- processed = true;
- arguments.Current.Values.Add(arg);
- }
- }
-
- if (!processed)
- {
- if (HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"))
- {
- continue;
- }
-
- break;
- }
- }
-
- if (option != null)
- {
- command.ShowHint();
- throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'");
- }
-
- return command.Invoke();
- }
-
- // Helper method that adds a help option
- public CommandOption HelpOption(string template)
- {
- // Help option is special because we stop parsing once we see it
- // So we store it separately for further use
- OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue);
-
- return OptionHelp;
- }
-
- public CommandOption VersionOption(string template,
- string shortFormVersion,
- string longFormVersion = null)
- {
- if (longFormVersion == null)
- {
- return VersionOption(template, () => shortFormVersion);
- }
- else
- {
- return VersionOption(template, () => shortFormVersion, () => longFormVersion);
- }
- }
-
- // Helper method that adds a version option
- public CommandOption VersionOption(string template,
- Func<string> shortFormVersionGetter,
- Func<string> longFormVersionGetter = null)
- {
- // Version option is special because we stop parsing once we see it
- // So we store it separately for further use
- OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue);
- ShortVersionGetter = shortFormVersionGetter;
- LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
-
- return OptionVersion;
- }
-
- // Show short hint that reminds users to use help option
- public void ShowHint()
- {
- if (OptionHelp != null)
- {
- Out.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName));
- }
- }
-
- // Show full help
- public void ShowHelp(string commandName = null)
- {
- for (var cmd = this; cmd != null; cmd = cmd.Parent)
- {
- cmd.IsShowingInformation = true;
- }
-
- Out.WriteLine(GetHelpText(commandName));
- }
-
- public virtual string GetHelpText(string commandName = null)
- {
- var headerBuilder = new StringBuilder("Usage:");
- for (var cmd = this; cmd != null; cmd = cmd.Parent)
- {
- headerBuilder.Insert(6, string.Format(" {0}", cmd.Name));
- }
-
- CommandLineApplication target;
-
- if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
- {
- target = this;
- }
- else
- {
- target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
-
- if (target != null)
- {
- headerBuilder.AppendFormat(" {0}", commandName);
- }
- else
- {
- // The command name is invalid so don't try to show help for something that doesn't exist
- target = this;
- }
-
- }
-
- var optionsBuilder = new StringBuilder();
- var commandsBuilder = new StringBuilder();
- var argumentsBuilder = new StringBuilder();
-
- var arguments = target.Arguments.Where(a => a.ShowInHelpText).ToList();
- if (arguments.Any())
- {
- headerBuilder.Append(" [arguments]");
-
- argumentsBuilder.AppendLine();
- argumentsBuilder.AppendLine("Arguments:");
- var maxArgLen = arguments.Max(a => a.Name.Length);
- var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxArgLen + 2);
- foreach (var arg in arguments)
- {
- argumentsBuilder.AppendFormat(outputFormat, arg.Name, arg.Description);
- argumentsBuilder.AppendLine();
- }
- }
-
- var options = target.GetOptions().Where(o => o.ShowInHelpText).ToList();
- if (options.Any())
- {
- headerBuilder.Append(" [options]");
-
- optionsBuilder.AppendLine();
- optionsBuilder.AppendLine("Options:");
- var maxOptLen = options.Max(o => o.Template.Length);
- var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2);
- foreach (var opt in options)
- {
- optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
- optionsBuilder.AppendLine();
- }
- }
-
- var commands = target.Commands.Where(c => c.ShowInHelpText).ToList();
- if (commands.Any())
- {
- headerBuilder.Append(" [command]");
-
- commandsBuilder.AppendLine();
- commandsBuilder.AppendLine("Commands:");
- var maxCmdLen = commands.Max(c => c.Name.Length);
- var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2);
- foreach (var cmd in commands.OrderBy(c => c.Name))
- {
- commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
- commandsBuilder.AppendLine();
- }
-
- if (OptionHelp != null)
- {
- commandsBuilder.AppendLine();
- commandsBuilder.AppendFormat($"Use \"{target.Name} [command] --{OptionHelp.LongName}\" for more information about a command.");
- commandsBuilder.AppendLine();
- }
- }
-
- if (target.AllowArgumentSeparator)
- {
- headerBuilder.Append(" [[--] <arg>...]");
- }
-
- headerBuilder.AppendLine();
-
- var nameAndVersion = new StringBuilder();
- nameAndVersion.AppendLine(GetFullNameAndVersion());
- nameAndVersion.AppendLine();
-
- return nameAndVersion.ToString()
- + headerBuilder.ToString()
- + argumentsBuilder.ToString()
- + optionsBuilder.ToString()
- + commandsBuilder.ToString()
- + target.ExtendedHelpText;
- }
-
- public void ShowVersion()
- {
- for (var cmd = this; cmd != null; cmd = cmd.Parent)
- {
- cmd.IsShowingInformation = true;
- }
-
- Out.WriteLine(FullName);
- Out.WriteLine(LongVersionGetter());
- }
-
- public string GetFullNameAndVersion()
- {
- return ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
- }
-
- public void ShowRootCommandFullNameAndVersion()
- {
- var rootCmd = this;
- while (rootCmd.Parent != null)
- {
- rootCmd = rootCmd.Parent;
- }
-
- Out.WriteLine(rootCmd.GetFullNameAndVersion());
- Out.WriteLine();
- }
-
- 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
- {
- // Store all remaining arguments for later use.
- command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
- return false;
- }
- }
-
- private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
- {
- private readonly IEnumerator<CommandArgument> _enumerator;
-
- public CommandArgumentEnumerator(IEnumerator<CommandArgument> enumerator)
- {
- _enumerator = enumerator;
- }
-
- public CommandArgument Current
- {
- get
- {
- return _enumerator.Current;
- }
- }
-
- object IEnumerator.Current
- {
- get
- {
- return Current;
- }
- }
-
- public void Dispose()
- {
- _enumerator.Dispose();
- }
-
- public bool MoveNext()
- {
- if (Current == null || !Current.MultipleValues)
- {
- return _enumerator.MoveNext();
- }
-
- // If current argument allows multiple values, we don't move forward and
- // all later values will be added to current CommandArgument.Values
- return true;
- }
-
- public void Reset()
- {
- _enumerator.Reset();
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.IO;
-using System.Linq;
-using Microsoft.Extensions.CommandLineUtils;
-using Xunit;
-
-namespace Microsoft.Extensions.Internal
-{
- public class CommandLineApplicationTests
- {
- [Fact]
- public void CommandNameCanBeMatched()
- {
- var called = false;
-
- var app = new CommandLineApplication();
- app.Command("test", c =>
- {
- c.OnExecute(() =>
- {
- called = true;
- return 5;
- });
- });
-
- var result = app.Execute("test");
- Assert.Equal(5, result);
- Assert.True(called);
- }
-
- [Fact]
- public void RemainingArgsArePassed()
- {
- CommandArgument first = null;
- CommandArgument second = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Argument("first", "First argument");
- second = c.Argument("second", "Second argument");
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "one", "two");
-
- Assert.Equal("one", first.Value);
- Assert.Equal("two", second.Value);
- }
-
- [Fact]
- public void ExtraArgumentCausesException()
- {
- CommandArgument first = null;
- CommandArgument second = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Argument("first", "First argument");
- second = c.Argument("second", "Second argument");
- c.OnExecute(() => 0);
- });
-
- var ex = Assert.Throws<CommandParsingException>(() => app.Execute("test", "one", "two", "three"));
-
- 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()
- {
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- c.Argument("first", "First argument");
- c.Argument("second", "Second argument");
- c.OnExecute(() => 0);
- });
-
- var ex = Assert.Throws<CommandParsingException>(() => app.Execute("test2", "one", "two", "three"));
-
- Assert.Contains("test2", ex.Message);
- }
-
- [Fact]
- public void MultipleValuesArgumentConsumesAllArgumentValues()
- {
- CommandArgument argument = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- argument = c.Argument("arg", "Argument that allows multiple values", multipleValues: true);
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "one", "two", "three", "four", "five");
-
- Assert.Equal(new[] { "one", "two", "three", "four", "five" }, argument.Values);
- }
-
- [Fact]
- public void MultipleValuesArgumentConsumesAllRemainingArgumentValues()
- {
- CommandArgument first = null;
- CommandArgument second = null;
- CommandArgument third = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Argument("first", "First argument");
- second = c.Argument("second", "Second argument");
- third = c.Argument("third", "Third argument that allows multiple values", multipleValues: true);
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "one", "two", "three", "four", "five");
-
- Assert.Equal("one", first.Value);
- Assert.Equal("two", second.Value);
- Assert.Equal(new[] { "three", "four", "five" }, third.Values);
- }
-
- [Fact]
- public void MultipleValuesArgumentMustBeTheLastArgument()
- {
- var app = new CommandLineApplication();
- app.Argument("first", "First argument", multipleValues: true);
- var ex = Assert.Throws<InvalidOperationException>(() => app.Argument("second", "Second argument"));
-
- Assert.Contains($"The last argument 'first' accepts multiple values. No more argument can be added.",
- ex.Message);
- }
-
- [Fact]
- public void OptionSwitchMayBeProvided()
- {
- CommandOption first = null;
- CommandOption second = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Option("--first <NAME>", "First argument", CommandOptionType.SingleValue);
- second = c.Option("--second <NAME>", "Second argument", CommandOptionType.SingleValue);
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "--first", "one", "--second", "two");
-
- Assert.Equal("one", first.Values[0]);
- Assert.Equal("two", second.Values[0]);
- }
-
- [Fact]
- public void OptionValueMustBeProvided()
- {
- CommandOption first = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Option("--first <NAME>", "First argument", CommandOptionType.SingleValue);
- c.OnExecute(() => 0);
- });
-
- var ex = Assert.Throws<CommandParsingException>(() => app.Execute("test", "--first"));
-
- Assert.Contains($"Missing value for option '{first.LongName}'", ex.Message);
- }
-
- [Fact]
- public void ValuesMayBeAttachedToSwitch()
- {
- CommandOption first = null;
- CommandOption second = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Option("--first <NAME>", "First argument", CommandOptionType.SingleValue);
- second = c.Option("--second <NAME>", "Second argument", CommandOptionType.SingleValue);
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "--first=one", "--second:two");
-
- Assert.Equal("one", first.Values[0]);
- Assert.Equal("two", second.Values[0]);
- }
-
- [Fact]
- public void ShortNamesMayBeDefined()
- {
- CommandOption first = null;
- CommandOption second = null;
-
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- first = c.Option("-1 --first <NAME>", "First argument", CommandOptionType.SingleValue);
- second = c.Option("-2 --second <NAME>", "Second argument", CommandOptionType.SingleValue);
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", "-1=one", "-2", "two");
-
- Assert.Equal("one", first.Values[0]);
- Assert.Equal("two", second.Values[0]);
- }
-
- [Fact]
- public void ThrowsExceptionOnUnexpectedCommandOrArgumentByDefault()
- {
- var unexpectedArg = "UnexpectedArg";
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", unexpectedArg));
- Assert.Equal($"Unrecognized command or argument '{unexpectedArg}'", exception.Message);
- }
-
- [Fact]
- public void AllowNoThrowBehaviorOnUnexpectedArgument()
- {
- var unexpectedArg = "UnexpectedArg";
- var app = new CommandLineApplication();
-
- var testCmd = app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- },
- throwOnUnexpectedArg: false);
-
- // (does not throw)
- app.Execute("test", unexpectedArg);
- var arg = Assert.Single(testCmd.RemainingArguments);
- 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()
- {
- var unexpectedOption = "--UnexpectedOption";
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", unexpectedOption));
- Assert.Equal($"Unrecognized option '{unexpectedOption}'", exception.Message);
- }
-
- [Fact]
- public void AllowNoThrowBehaviorOnUnexpectedLongOption()
- {
- var unexpectedOption = "--UnexpectedOption";
- var app = new CommandLineApplication();
-
- var testCmd = app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- },
- throwOnUnexpectedArg: false);
-
- // (does not throw)
- app.Execute("test", unexpectedOption);
- var arg = Assert.Single(testCmd.RemainingArguments);
- 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()
- {
- var unexpectedOption = "-uexp";
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", unexpectedOption));
- Assert.Equal($"Unrecognized option '{unexpectedOption}'", exception.Message);
- }
-
- [Fact]
- public void AllowNoThrowBehaviorOnUnexpectedShortOption()
- {
- var unexpectedOption = "-uexp";
- var app = new CommandLineApplication();
-
- var testCmd = app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- },
- throwOnUnexpectedArg: false);
-
- // (does not throw)
- app.Execute("test", unexpectedOption);
- var arg = Assert.Single(testCmd.RemainingArguments);
- Assert.Equal(unexpectedOption, arg);
- }
-
- [Fact]
- public void ThrowsExceptionOnUnexpectedSymbolOptionByDefault()
- {
- var unexpectedOption = "-?";
- var app = new CommandLineApplication();
-
- app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", unexpectedOption));
- Assert.Equal($"Unrecognized option '{unexpectedOption}'", exception.Message);
- }
-
- [Fact]
- public void AllowNoThrowBehaviorOnUnexpectedSymbolOption()
- {
- var unexpectedOption = "-?";
- var app = new CommandLineApplication();
-
- var testCmd = app.Command("test", c =>
- {
- c.OnExecute(() => 0);
- },
- throwOnUnexpectedArg: false);
-
- // (does not throw)
- app.Execute("test", unexpectedOption);
- var arg = Assert.Single(testCmd.RemainingArguments);
- Assert.Equal(unexpectedOption, arg);
- }
-
- [Fact]
- public void ThrowsExceptionOnUnexpectedOptionBeforeValidSubcommandByDefault()
- {
- var unexpectedOption = "--unexpected";
- CommandLineApplication subCmd = null;
- var app = new CommandLineApplication();
-
- app.Command("k", c =>
- {
- subCmd = c.Command("run", _ => { });
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("k", unexpectedOption, "run"));
- 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";
- var app = new CommandLineApplication();
-
- CommandLineApplication subCmd = null;
- var testCmd = app.Command("k", c =>
- {
- subCmd = c.Command("run", _ => { }, throwOnUnexpectedArg: false);
- c.OnExecute(() => 0);
- });
-
- // (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()
- {
- var app = new CommandLineApplication();
- var optionA = app.Option("-a|--option-a", "", CommandOptionType.SingleValue, inherited: true);
- string optionAValue = null;
-
- var optionB = app.Option("-b", "", CommandOptionType.SingleValue, inherited: false);
-
- var subcmd = app.Command("subcmd", c =>
- {
- c.OnExecute(() =>
- {
- optionAValue = optionA.Value();
- return 0;
- });
- });
-
- Assert.Equal(2, app.GetOptions().Count());
- Assert.Single(subcmd.GetOptions());
-
- app.Execute("-a", "A1", "subcmd");
- Assert.Equal("A1", optionAValue);
-
- Assert.Throws<CommandParsingException>(() => app.Execute("subcmd", "-b", "B"));
-
- Assert.Contains("-a|--option-a", subcmd.GetHelpText());
- }
-
- [Fact]
- public void NestedOptionConflictThrows()
- {
- var app = new CommandLineApplication();
- app.Option("-a|--always", "Top-level", CommandOptionType.SingleValue, inherited: true);
- app.Command("subcmd", c =>
- {
- c.Option("-a|--ask", "Nested", CommandOptionType.SingleValue);
- });
-
- Assert.Throws<InvalidOperationException>(() => app.Execute("subcmd", "-a", "b"));
- }
-
- [Fact]
- public void OptionsWithSameName()
- {
- var app = new CommandLineApplication();
- var top = app.Option("-a|--always", "Top-level", CommandOptionType.SingleValue, inherited: false);
- CommandOption nested = null;
- app.Command("subcmd", c =>
- {
- nested = c.Option("-a|--ask", "Nested", CommandOptionType.SingleValue);
- });
-
- app.Execute("-a", "top");
- Assert.Equal("top", top.Value());
- Assert.Null(nested.Value());
-
- top.Values.Clear();
-
- app.Execute("subcmd", "-a", "nested");
- Assert.Null(top.Value());
- Assert.Equal("nested", nested.Value());
- }
-
- [Fact]
- public void NestedInheritedOptions()
- {
- string globalOptionValue = null, nest1OptionValue = null, nest2OptionValue = null;
-
- var app = new CommandLineApplication();
- CommandLineApplication subcmd2 = null;
- var g = app.Option("-g|--global", "Global option", CommandOptionType.SingleValue, inherited: true);
- var subcmd1 = app.Command("lvl1", s1 =>
- {
- var n1 = s1.Option("--nest1", "Nested one level down", CommandOptionType.SingleValue, inherited: true);
- subcmd2 = s1.Command("lvl2", s2 =>
- {
- var n2 = s2.Option("--nest2", "Nested one level down", CommandOptionType.SingleValue, inherited: true);
- s2.HelpOption("-h|--help");
- s2.OnExecute(() =>
- {
- globalOptionValue = g.Value();
- nest1OptionValue = n1.Value();
- nest2OptionValue = n2.Value();
- return 0;
- });
- });
- });
-
- Assert.DoesNotContain(app.GetOptions(), o => o.LongName == "nest2");
- Assert.DoesNotContain(app.GetOptions(), o => o.LongName == "nest1");
- Assert.Contains(app.GetOptions(), o => o.LongName == "global");
-
- Assert.DoesNotContain(subcmd1.GetOptions(), o => o.LongName == "nest2");
- Assert.Contains(subcmd1.GetOptions(), o => o.LongName == "nest1");
- Assert.Contains(subcmd1.GetOptions(), o => o.LongName == "global");
-
- Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "nest2");
- Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "nest1");
- Assert.Contains(subcmd2.GetOptions(), o => o.LongName == "global");
-
- Assert.Throws<CommandParsingException>(() => app.Execute("--nest2", "N2", "--nest1", "N1", "-g", "G"));
- Assert.Throws<CommandParsingException>(() => app.Execute("lvl1", "--nest2", "N2", "--nest1", "N1", "-g", "G"));
-
- app.Execute("lvl1", "lvl2", "--nest2", "N2", "-g", "G", "--nest1", "N1");
- Assert.Equal("G", globalOptionValue);
- Assert.Equal("N1", nest1OptionValue);
- Assert.Equal("N2", nest2OptionValue);
- }
-
- [Theory]
- [InlineData(new string[0], new string[0], null)]
- [InlineData(new[] { "--" }, new string[0], null)]
- [InlineData(new[] { "-t", "val" }, new string[0], "val")]
- [InlineData(new[] { "-t", "val", "--" }, new string[0], "val")]
- [InlineData(new[] { "--top", "val", "--", "a" }, new[] { "a" }, "val")]
- [InlineData(new[] { "--", "a", "--top", "val" }, new[] { "a", "--top", "val" }, null)]
- [InlineData(new[] { "-t", "val", "--", "a", "--", "b" }, new[] { "a", "--", "b" }, "val")]
- [InlineData(new[] { "--", "--help" }, new[] { "--help" }, null)]
- [InlineData(new[] { "--", "--version" }, new[] { "--version" }, null)]
- public void ArgumentSeparator(string[] input, string[] expectedRemaining, string topLevelValue)
- {
- var app = new CommandLineApplication(throwOnUnexpectedArg: false)
- {
- AllowArgumentSeparator = 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.False(optHelp.HasValue());
- Assert.False(optVersion.HasValue());
- 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()
- {
- var app = new CommandLineApplication()
- {
- Name = "ninja-app",
- Description = "You can't see it until it is too late"
- };
-
- app.Command("star", c =>
- {
- c.Option("--points <p>", "How many", CommandOptionType.MultipleValue);
- c.ShowInHelpText = false;
- });
- app.Option("--smile", "Be a nice ninja", CommandOptionType.NoValue, o => { o.ShowInHelpText = false; });
-
- var a = app.Argument("name", "Pseudonym, of course");
- a.ShowInHelpText = false;
-
- var help = app.GetHelpText();
-
- Assert.Contains("ninja-app", help);
- Assert.DoesNotContain("--points", help);
- Assert.DoesNotContain("--smile", help);
- Assert.DoesNotContain("name", help);
- }
-
- [Fact]
- public void HelpTextUsesHelpOptionName()
- {
- var app = new CommandLineApplication
- {
- Name = "superhombre"
- };
-
- app.HelpOption("--ayuda-me");
- var help = app.GetHelpText();
- Assert.Contains("--ayuda-me", help);
- }
-
- [Fact]
- public void HelpTextShowsArgSeparator()
- {
- var app = new CommandLineApplication(throwOnUnexpectedArg: false)
- {
- Name = "proxy-command",
- AllowArgumentSeparator = true
- };
- app.HelpOption("-h|--help");
- Assert.Contains("Usage: proxy-command [options] [[--] <arg>...]", app.GetHelpText());
- }
-
- [Fact]
- public void HelpTextShowsExtendedHelp()
- {
- var app = new CommandLineApplication()
- {
- Name = "befuddle",
- ExtendedHelpText = @"
-Remarks:
- This command is so confusing that I want to include examples in the help text.
-
-Examples:
- dotnet befuddle -- I Can Haz Confusion Arguments
-"
- };
-
- Assert.Contains(app.ExtendedHelpText, app.GetHelpText());
- }
-
- [Theory]
- [InlineData(new[] { "--version", "--flag" }, "1.0")]
- [InlineData(new[] { "-V", "-f" }, "1.0")]
- [InlineData(new[] { "--help", "--flag" }, "some flag")]
- [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);
-
- app.Execute(input);
-
- outWriter.Flush();
- var outData = outWriter.ToString();
- Assert.Contains(expectedOutData, outData);
- Assert.False(optFlag.HasValue());
- }
-
- [Theory]
- [InlineData("-f:File1", "-f:File2")]
- [InlineData("--file:File1", "--file:File2")]
- [InlineData("--file", "File1", "--file", "File2")]
- public void ThrowsExceptionOnSingleValueOptionHavingTwoValues(params string[] inputOptions)
- {
- var app = new CommandLineApplication();
- app.Option("-f |--file", "some file", CommandOptionType.SingleValue);
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute(inputOptions));
-
- Assert.Equal("Unexpected value 'File2' for option 'file'", exception.Message);
- }
-
- [Theory]
- [InlineData("-v")]
- [InlineData("--verbose")]
- public void NoValueOptionCanBeSet(string input)
- {
- var app = new CommandLineApplication();
- var optVerbose = app.Option("-v |--verbose", "be verbose", CommandOptionType.NoValue);
-
- app.Execute(input);
-
- Assert.True(optVerbose.HasValue());
- }
-
- [Theory]
- [InlineData("-v:true")]
- [InlineData("--verbose:true")]
- public void ThrowsExceptionOnNoValueOptionHavingValue(string inputOption)
- {
- var app = new CommandLineApplication();
- app.Option("-v |--verbose", "be verbose", CommandOptionType.NoValue);
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute(inputOption));
-
- Assert.Equal("Unexpected value 'true' for option 'verbose'", exception.Message);
- }
-
- [Fact]
- public void ThrowsExceptionOnEmptyCommandOrArgument()
- {
- var inputOption = String.Empty;
- var app = new CommandLineApplication();
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute(inputOption));
-
- Assert.Equal($"Unrecognized command or argument '{inputOption}'", exception.Message);
- }
-
- [Fact]
- public void ThrowsExceptionOnInvalidOption()
- {
- var inputOption = "-";
- var app = new CommandLineApplication();
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute(inputOption));
-
- Assert.Equal($"Unrecognized option '{inputOption}'", exception.Message);
- }
-
- [Fact]
- public void TreatUnmatchedOptionsAsArguments()
- {
- CommandArgument first = null;
- CommandArgument second = null;
-
- CommandOption firstOption = null;
- CommandOption secondOption = null;
-
- var firstUnmatchedOption = "-firstUnmatchedOption";
- var firstActualOption = "-firstActualOption";
- var seconUnmatchedOption = "--secondUnmatchedOption";
- var secondActualOption = "--secondActualOption";
-
- var app = new CommandLineApplication(treatUnmatchedOptionsAsArguments: true);
-
- app.Command("test", c =>
- {
- firstOption = c.Option("-firstActualOption", "first option", CommandOptionType.NoValue);
- secondOption = c.Option("--secondActualOption", "second option", CommandOptionType.NoValue);
-
- first = c.Argument("first", "First argument");
- second = c.Argument("second", "Second argument");
- c.OnExecute(() => 0);
- });
-
- app.Execute("test", firstUnmatchedOption, firstActualOption, seconUnmatchedOption, secondActualOption);
-
- Assert.Equal(firstUnmatchedOption, first.Value);
- Assert.Equal(seconUnmatchedOption, second.Value);
-
- Assert.Equal(firstActualOption, firstOption.Template);
- Assert.Equal(secondActualOption, secondOption.Template);
- }
-
- [Fact]
- public void ThrowExceptionWhenUnmatchedOptionAndTreatUnmatchedOptionsAsArgumentsIsFalse()
- {
- CommandArgument first = null;
-
- var firstOption = "-firstUnmatchedOption";
-
- var app = new CommandLineApplication(treatUnmatchedOptionsAsArguments: false);
- app.Command("test", c =>
- {
- first = c.Argument("first", "First argument");
- c.OnExecute(() => 0);
- });
-
- var exception = Assert.Throws<CommandParsingException>(() => app.Execute("test", firstOption));
-
- Assert.Equal($"Unrecognized option '{firstOption}'", exception.Message);
- }
- }
-}