Move Spectre.Console.Cli to it's own package

This commit is contained in:
Patrik Svensson
2022-05-14 22:56:36 +02:00
committed by Patrik Svensson
parent b600832e00
commit 36ca22ffac
262 changed files with 736 additions and 48 deletions

View File

@ -0,0 +1,18 @@
namespace Spectre.Console.Tests;
public static class Constants
{
public static string[] VersionCommand { get; } =
new[]
{
CliConstants.Commands.Branch,
CliConstants.Commands.Version,
};
public static string[] XmlDocCommand { get; } =
new[]
{
CliConstants.Commands.Branch,
CliConstants.Commands.XmlDoc,
};
}

View File

@ -0,0 +1,45 @@
using SystemConsole = System.Console;
namespace Spectre.Console.Tests.Data;
public abstract class AnimalCommand<TSettings> : Command<TSettings>
where TSettings : CommandSettings
{
protected void DumpSettings(CommandContext context, TSettings settings)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (settings == null)
{
throw new ArgumentNullException(nameof(settings));
}
var properties = settings.GetType().GetProperties();
foreach (var group in properties.GroupBy(x => x.DeclaringType).Reverse())
{
SystemConsole.WriteLine();
SystemConsole.ForegroundColor = ConsoleColor.Yellow;
SystemConsole.WriteLine(group.Key.FullName);
SystemConsole.ResetColor();
foreach (var property in group)
{
SystemConsole.WriteLine($" {property.Name} = {property.GetValue(settings)}");
}
}
if (context.Remaining.Raw.Count > 0)
{
SystemConsole.WriteLine();
SystemConsole.ForegroundColor = ConsoleColor.Yellow;
SystemConsole.WriteLine("Remaining:");
SystemConsole.ResetColor();
SystemConsole.WriteLine(string.Join(", ", context.Remaining));
}
SystemConsole.WriteLine();
}
}

View File

@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Data;
public class CatCommand : AnimalCommand<CatSettings>
{
public override int Execute(CommandContext context, CatSettings settings)
{
DumpSettings(context, settings);
return 0;
}
}

View File

@ -0,0 +1,31 @@
namespace Spectre.Console.Tests.Data;
[Description("The dog command.")]
public class DogCommand : AnimalCommand<DogSettings>
{
public override ValidationResult Validate(CommandContext context, DogSettings settings)
{
if (context is null)
{
throw new System.ArgumentNullException(nameof(context));
}
if (settings is null)
{
throw new System.ArgumentNullException(nameof(settings));
}
if (settings.Age > 100 && !context.Remaining.Raw.Contains("zombie"))
{
return ValidationResult.Error("Dog is too old...");
}
return base.Validate(context, settings);
}
public override int Execute(CommandContext context, DogSettings settings)
{
DumpSettings(context, settings);
return 0;
}
}

View File

@ -0,0 +1,34 @@
namespace Spectre.Console.Tests.Data;
public sealed class DumpRemainingCommand : Command<EmptyCommandSettings>
{
private readonly IAnsiConsole _console;
public DumpRemainingCommand(IAnsiConsole console)
{
_console = console;
}
public override int Execute(CommandContext context, EmptyCommandSettings settings)
{
if (context.Remaining.Raw.Count > 0)
{
_console.WriteLine("# Raw");
foreach (var item in context.Remaining.Raw)
{
_console.WriteLine(item);
}
}
if (context.Remaining.Parsed.Count > 0)
{
_console.WriteLine("# Parsed");
foreach (var item in context.Remaining.Parsed)
{
_console.WriteLine(string.Format("{0}={1}", item.Key, string.Join(",", item.Select(x => x))));
}
}
return 0;
}
}

View File

@ -0,0 +1,9 @@
namespace Spectre.Console.Tests.Data;
public sealed class EmptyCommand : Command<EmptyCommandSettings>
{
public override int Execute(CommandContext context, EmptyCommandSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Data;
public sealed class GenericCommand<TSettings> : Command<TSettings>
where TSettings : CommandSettings
{
public override int Execute(CommandContext context, TSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Data;
[Description("The giraffe command.")]
public sealed class GiraffeCommand : Command<GiraffeSettings>
{
public override int Execute(CommandContext context, GiraffeSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,9 @@
namespace Spectre.Console.Tests.Data;
public sealed class HiddenOptionsCommand : Command<HiddenOptionSettings>
{
public override int Execute(CommandContext context, HiddenOptionSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,11 @@
namespace Spectre.Console.Tests.Data;
[Description("The horse command.")]
public class HorseCommand : AnimalCommand<MammalSettings>
{
public override int Execute(CommandContext context, MammalSettings settings)
{
DumpSettings(context, settings);
return 0;
}
}

View File

@ -0,0 +1,9 @@
namespace Spectre.Console.Tests.Data;
public sealed class InvalidCommand : Command<InvalidSettings>
{
public override int Execute(CommandContext context, InvalidSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Data;
[Description("The lion command.")]
public class LionCommand : AnimalCommand<LionSettings>
{
public override int Execute(CommandContext context, LionSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,12 @@
namespace Spectre.Console.Tests.Data;
public sealed class NoDescriptionCommand : Command<EmptyCommandSettings>
{
[CommandOption("-f|--foo <VALUE>")]
public int Foo { get; set; }
public override int Execute(CommandContext context, EmptyCommandSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,9 @@
namespace Spectre.Console.Tests.Data;
public class OptionVectorCommand : Command<OptionVectorSettings>
{
public override int Execute(CommandContext context, OptionVectorSettings settings)
{
return 0;
}
}

View File

@ -0,0 +1,13 @@
namespace Spectre.Console.Tests.Data;
public sealed class ThrowingCommand : Command<ThrowingCommandSettings>
{
public override int Execute(CommandContext context, ThrowingCommandSettings settings)
{
throw new InvalidOperationException("W00t?");
}
}
public sealed class ThrowingCommandSettings : CommandSettings
{
}

View File

@ -0,0 +1,14 @@
namespace Spectre.Console.Tests.Data;
public sealed class CatAgilityConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string stringValue)
{
return stringValue.Length;
}
return base.ConvertFrom(context, culture, value);
}
}

View File

@ -0,0 +1,14 @@
namespace Spectre.Console.Tests.Data;
public sealed class StringToIntegerConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string stringValue)
{
return int.Parse(stringValue, CultureInfo.InvariantCulture);
}
return base.ConvertFrom(context, culture, value);
}
}

View File

@ -0,0 +1,14 @@
namespace Spectre.Console.Tests.Data;
public abstract class AnimalSettings : CommandSettings
{
[CommandOption("-a|--alive|--not-dead")]
[Description("Indicates whether or not the animal is alive.")]
public bool IsAlive { get; set; }
[CommandArgument(1, "[LEGS]")]
[Description("The number of legs.")]
[EvenNumberValidator("Animals must have an even number of legs.")]
[PositiveNumberValidator("Number of legs must be greater than 0.")]
public int Legs { get; set; }
}

View File

@ -0,0 +1,19 @@
namespace Spectre.Console.Tests.Data;
public sealed class ArgumentOrderSettings : CommandSettings
{
[CommandArgument(0, "[QUX]")]
public int Qux { get; set; }
[CommandArgument(3, "<CORGI>")]
public int Corgi { get; set; }
[CommandArgument(1, "<BAR>")]
public int Bar { get; set; }
[CommandArgument(2, "<BAZ>")]
public int Baz { get; set; }
[CommandArgument(0, "<FOO>")]
public int Foo { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Spectre.Console.Tests.Data;
public class ArgumentVectorSettings : CommandSettings
{
[CommandArgument(0, "<Foos>")]
public string[] Foo { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace Spectre.Console.Tests.Data;
public class BarCommandSettings : FooCommandSettings
{
[CommandArgument(0, "<CORGI>")]
[Description("The corgi value.")]
public string Corgi { get; set; }
}

View File

@ -0,0 +1,11 @@
namespace Spectre.Console.Tests.Data;
public class CatSettings : MammalSettings
{
[CommandOption("--agility <VALUE>")]
[TypeConverter(typeof(CatAgilityConverter))]
[DefaultValue(10)]
[Description("The agility between 0 and 100.")]
[PositiveNumberValidator("Agility cannot be negative.")]
public int Agility { get; set; }
}

View File

@ -0,0 +1,20 @@
namespace Spectre.Console.Tests.Data;
public sealed class DogSettings : MammalSettings
{
[CommandArgument(0, "<AGE>")]
public int Age { get; set; }
[CommandOption("-g|--good-boy")]
public bool GoodBoy { get; set; }
public override ValidationResult Validate()
{
if (Name == "Tiger")
{
return ValidationResult.Error("Tiger is not a dog name!");
}
return ValidationResult.Success();
}
}

View File

@ -0,0 +1,5 @@
namespace Spectre.Console.Tests.Data;
public sealed class EmptySettings : CommandSettings
{
}

View File

@ -0,0 +1,8 @@
namespace Spectre.Console.Tests.Data;
public class FooCommandSettings : CommandSettings
{
[CommandArgument(0, "[QUX]")]
[Description("The qux value.")]
public string Qux { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace Spectre.Console.Tests.Data;
public sealed class GiraffeSettings : MammalSettings
{
[CommandArgument(0, "<LENGTH>")]
[Description("The option description.")]
public int Length { get; set; }
}

View File

@ -0,0 +1,16 @@
namespace Spectre.Console.Tests.Data;
public sealed class HiddenOptionSettings : CommandSettings
{
[CommandArgument(0, "<FOO>")]
[Description("Dummy argument FOO")]
public int Foo { get; set; }
[CommandOption("--bar", IsHidden = true)]
[Description("You should not be able to read this unless you used the 'cli explain' command with the '--hidden' option")]
public int Bar { get; set; }
[CommandOption("--baz")]
[Description("Dummy option BAZ")]
public int Baz { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Spectre.Console.Tests.Data;
public sealed class InvalidSettings : CommandSettings
{
[CommandOption("-f|--foo [BAR]")]
public string Value { get; set; }
}

View File

@ -0,0 +1,12 @@
namespace Spectre.Console.Tests.Data;
public class LionSettings : CatSettings
{
[CommandArgument(0, "<TEETH>")]
[Description("The number of teeth the lion has.")]
public int Teeth { get; set; }
[CommandOption("-c <CHILDREN>")]
[Description("The number of children the lion has.")]
public int Children { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Spectre.Console.Tests.Data;
public class MammalSettings : AnimalSettings
{
[CommandOption("-n|-p|--name|--pet-name <VALUE>")]
public string Name { get; set; }
}

View File

@ -0,0 +1,19 @@
namespace Spectre.Console.Tests.Data;
public class MultipleArgumentVectorSettings : CommandSettings
{
[CommandArgument(0, "<Foos>")]
public string[] Foo { get; set; }
[CommandArgument(0, "<Bars>")]
public string[] Bar { get; set; }
}
public class MultipleArgumentVectorSpecifiedFirstSettings : CommandSettings
{
[CommandArgument(1, "[Bar]")]
public string Bar { get; set; }
[CommandArgument(0, "<Foos>")]
public string[] Foo { get; set; }
}

View File

@ -0,0 +1,10 @@
namespace Spectre.Console.Tests.Data;
public class OptionVectorSettings : CommandSettings
{
[CommandOption("--foo")]
public string[] Foo { get; set; }
[CommandOption("--bar")]
public int[] Bar { get; set; }
}

View File

@ -0,0 +1,35 @@
namespace Spectre.Console.Tests.Data;
public sealed class OptionalArgumentWithDefaultValueSettings : CommandSettings
{
[CommandArgument(0, "[GREETING]")]
[DefaultValue("Hello World")]
public string Greeting { get; set; }
}
public sealed class OptionalArgumentWithPropertyInitializerSettings : CommandSettings
{
[CommandArgument(0, "[NAMES]")]
public string[] Names { get; set; } = Array.Empty<string>();
[CommandOption("-c")]
public int Count { get; set; } = 1;
[CommandOption("-v")]
public int Value { get; set; } = 0;
}
public sealed class OptionalArgumentWithDefaultValueAndTypeConverterSettings : CommandSettings
{
[CommandArgument(0, "[GREETING]")]
[DefaultValue("5")]
[TypeConverter(typeof(StringToIntegerConverter))]
public int Greeting { get; set; }
}
public sealed class RequiredArgumentWithDefaultValueSettings : CommandSettings
{
[CommandArgument(0, "<GREETING>")]
[DefaultValue("Hello World")]
public string Greeting { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Spectre.Console.Tests.Data;
public sealed class StringOptionSettings : CommandSettings
{
[CommandOption("-f|--foo")]
public string Foo { get; set; }
}

View File

@ -0,0 +1,25 @@
namespace Spectre.Console.Tests.Data;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class EvenNumberValidatorAttribute : ParameterValidationAttribute
{
public EvenNumberValidatorAttribute(string errorMessage)
: base(errorMessage)
{
}
public override ValidationResult Validate(CommandParameterContext context)
{
if (context.Value is int integer)
{
if (integer % 2 == 0)
{
return ValidationResult.Success();
}
return ValidationResult.Error($"Number is not even ({context.Parameter.PropertyName}).");
}
throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
}
}

View File

@ -0,0 +1,25 @@
namespace Spectre.Console.Tests.Data;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class PositiveNumberValidatorAttribute : ParameterValidationAttribute
{
public PositiveNumberValidatorAttribute(string errorMessage)
: base(errorMessage)
{
}
public override ValidationResult Validate(CommandParameterContext context)
{
if (context.Value is int integer)
{
if (integer > 0)
{
return ValidationResult.Success();
}
return ValidationResult.Error($"Number is not greater than 0 ({context.Parameter.PropertyName}).");
}
throw new InvalidOperationException($"Parameter is not a number ({context.Parameter.PropertyName}).");
}
}

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Arguments can not contain options.
--foo <BAR>
^^^^^ Not permitted

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Encountered invalid character '$' in option name.
--f$oo
^ Invalid character

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Encountered invalid character '$' in value name.
-f|--foo <F$OO>
^ Invalid character

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Long option names must consist of more than one character.
--f
^ Invalid option name

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
No long or short name for option has been specified.
<FOO>
^^^^^ Missing option. Was this meant to be an argument?

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Multiple option values are not supported.
-f|--foo <FOO> <BAR>
^^^^^ Too many option values

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Multiple values are not supported.
<FOO> <BAR>
^^^^^ Too many values

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Option names cannot start with a digit.
--1foo
^^^^ Invalid option name

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Options without name are not allowed.
--foo|-
^ Missing option name

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Short option names can not be longer than one character.
--foo|-bar
^^^ Invalid option name

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Encountered unexpected character '$'.
<FOO> $ <BAR>
^ Unexpected character

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Encountered unterminated value name 'BAR'.
--foo|-f <BAR
^^^^ Unterminated value name

View File

@ -0,0 +1,5 @@
Error: An error occured when parsing template.
Values without name are not allowed.
<>
^^ Missing value name

View File

@ -0,0 +1,12 @@
USAGE:
myapp <FOO> <BAR> <BAZ> <CORGI> [QUX] [OPTIONS]
ARGUMENTS:
<FOO>
<BAR>
<BAZ>
<CORGI>
[QUX]
OPTIONS:
-h, --help Prints help information

View File

@ -0,0 +1,14 @@
USAGE:
myapp cat [LEGS] [OPTIONS] <COMMAND>
ARGUMENTS:
[LEGS] The number of legs
OPTIONS:
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> The agility between 0 and 100
COMMANDS:
lion <TEETH> The lion command

View File

@ -0,0 +1,16 @@
USAGE:
myapp animal [LEGS] [OPTIONS] <COMMAND>
EXAMPLES:
myapp animal --help
ARGUMENTS:
[LEGS] The number of legs
OPTIONS:
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
COMMANDS:
dog <AGE> The dog command
horse The horse command

View File

@ -0,0 +1,13 @@
USAGE:
myapp <TEETH> [LEGS] [OPTIONS]
ARGUMENTS:
<TEETH> The number of teeth the lion has
[LEGS] The number of legs
OPTIONS:
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> The agility between 0 and 100
-c <CHILDREN> The number of children the lion has

View File

@ -0,0 +1,16 @@
USAGE:
myapp <TEETH> [LEGS] [OPTIONS]
EXAMPLES:
myapp 12 -c 3
ARGUMENTS:
<TEETH> The number of teeth the lion has
[LEGS] The number of legs
OPTIONS:
-h, --help Prints help information
-a, --alive Indicates whether or not the animal is alive
-n, --name <VALUE>
--agility <VALUE> The agility between 0 and 100
-c <CHILDREN> The number of children the lion has

View File

@ -0,0 +1,9 @@
USAGE:
myapp <FOO> [OPTIONS]
ARGUMENTS:
<FOO> Dummy argument FOO
OPTIONS:
-h, --help Prints help information
--baz Dummy option BAZ

View File

@ -0,0 +1,10 @@
USAGE:
myapp [OPTIONS] <COMMAND>
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
dog <AGE> The dog command
horse The horse command

View File

@ -0,0 +1,9 @@
USAGE:
myapp cat [LEGS] lion <TEETH> [OPTIONS]
ARGUMENTS:
<TEETH> The number of teeth the lion has
OPTIONS:
-h, --help Prints help information
-c <CHILDREN> The number of children the lion has

View File

@ -0,0 +1,9 @@
USAGE:
myapp [OPTIONS] <COMMAND>
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
bar

View File

@ -0,0 +1,11 @@
USAGE:
myapp [OPTIONS] <COMMAND>
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
dog <AGE> The dog command
horse The horse command
giraffe <LENGTH> The giraffe command

View File

@ -0,0 +1,14 @@
USAGE:
myapp [OPTIONS] <COMMAND>
EXAMPLES:
myapp dog --name Rufus --age 12 --good-boy
myapp horse --name Brutus
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
dog <AGE> The dog command
horse The horse command

View File

@ -0,0 +1,14 @@
USAGE:
myapp [OPTIONS] <COMMAND>
EXAMPLES:
myapp dog --name Rufus --age 12 --good-boy
myapp horse --name Brutus
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
dog <AGE> The dog command
horse The horse command

View File

@ -0,0 +1,13 @@
USAGE:
myapp [OPTIONS] <COMMAND>
EXAMPLES:
myapp animal dog --name Rufus --age 12 --good-boy
myapp animal horse --name Brutus
OPTIONS:
-h, --help Prints help information
-v, --version Prints version information
COMMANDS:
animal The animal command

View File

@ -0,0 +1,4 @@
Error: Flags cannot be assigned a value.
dog --alive foo
^^^^^^^ Can't assign value

View File

@ -0,0 +1,4 @@
Error: Flags cannot be assigned a value.
dog -a foo
^^ Can't assign value

View File

@ -0,0 +1,4 @@
Error: Short option does not have a valid name.
dog -f0o
^ Not a valid name for a short option

View File

@ -0,0 +1,4 @@
Error: Invalid long option name.
dog --f€oo
^ Invalid character

View File

@ -0,0 +1,4 @@
Error: Invalid long option name.
dog --
^^ Did you forget the option name?

View File

@ -0,0 +1,4 @@
Error: Invalid long option name.
dog --f
^^^ Did you mean -f?

View File

@ -0,0 +1,4 @@
Error: Invalid long option name.
dog --1foo
^^^^^^ Option names cannot start with a digit

View File

@ -0,0 +1,4 @@
Error: Could not match 'baz' with an argument.
giraffe foo bar baz
^^^ Could not match to argument

View File

@ -0,0 +1,4 @@
Error: Option 'name' is defined but no value has been provided.
dog --name
^^^^^^ No value provided

View File

@ -0,0 +1,4 @@
Error: Option 'name' is defined but no value has been provided.
dog -n
^^ No value provided

View File

@ -0,0 +1,4 @@
Error: Option does not have a name.
dog -
^ Did you forget the option name?

View File

@ -0,0 +1,4 @@
Error: Expected an option value.
dog --foo=
^ Did you forget the option value?

View File

@ -0,0 +1,4 @@
Error: Expected an option value.
dog --foo:
^ Did you forget the option value?

View File

@ -0,0 +1,4 @@
Error: Expected an option value.
dog -f=
^ Did you forget the option value?

View File

@ -0,0 +1,4 @@
Error: Expected an option value.
dog -f:
^ Did you forget the option value?

View File

@ -0,0 +1,3 @@
# Raw
/c
set && pause

View File

@ -0,0 +1,4 @@
Error: Unexpected option 'foo'.
--foo
^^^^^ Did you forget the command?

View File

@ -0,0 +1,4 @@
Error: Unexpected option 'f'.
-f
^^ Did you forget the command?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'cat'.
cat 14
^^^ No such command

View File

@ -0,0 +1,4 @@
Error: Unknown command 'other'.
empty other
^^^^^ No such command

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
dog bat 14
^^^ Did you mean 'cat'?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
bat 14
^^^ Did you mean 'cat'?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
bat
^^^ Did you mean 'cat'?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
dog bat
^^^ Did you mean 'cat'?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
qux bat
^^^ Did you mean 'bar'?

View File

@ -0,0 +1,4 @@
Error: Unknown command 'bat'.
foo qux bat
^^^ Did you mean 'bar'?

View File

@ -0,0 +1,4 @@
Error: Unknown option 'unknown'.
dog --unknown
^^^^^^^^^ Unknown option

View File

@ -0,0 +1,4 @@
Error: Unknown option 'u'.
dog -u
^^ Unknown option

View File

@ -0,0 +1,4 @@
Error: Encountered unterminated quoted string 'Rufus'.
--name "Rufus
^^^^^^ Did you forget the closing quotation mark?

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--DEFAULT COMMAND-->
<Command Name="__default_command" IsBranch="false" IsDefault="true" ClrType="Spectre.Console.Tests.Data.HiddenOptionsCommand" Settings="Spectre.Console.Tests.Data.HiddenOptionSettings">
<Parameters>
<Argument Name="FOO" Position="0" Required="true" Kind="scalar" ClrType="System.Int32">
<Description>Dummy argument FOO</Description>
</Argument>
<Option Short="" Long="baz" Value="NULL" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>Dummy option BAZ</Description>
</Option>
</Parameters>
</Command>
</Model>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--ANIMAL-->
<Command Name="animal" IsBranch="true" Settings="Spectre.Console.Tests.Data.AnimalSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
</Parameters>
<!--MAMMAL-->
<Command Name="mammal" IsBranch="true" Settings="Spectre.Console.Tests.Data.MammalSettings">
<Parameters>
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
<!--DOG-->
<Command Name="dog" IsBranch="false" ClrType="Spectre.Console.Tests.Data.DogCommand" Settings="Spectre.Console.Tests.Data.DogSettings">
<Parameters>
<Argument Name="AGE" Position="0" Required="true" Kind="scalar" ClrType="System.Int32" />
<Option Short="g" Long="good-boy" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean" />
</Parameters>
</Command>
<!--HORSE-->
<Command Name="horse" IsBranch="false" ClrType="Spectre.Console.Tests.Data.HorseCommand" Settings="Spectre.Console.Tests.Data.MammalSettings">
<Parameters>
<Option Shadowed="true" Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
</Command>
</Command>
</Model>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--DOG-->
<Command Name="dog" IsBranch="false" ClrType="Spectre.Console.Tests.Data.DogCommand" Settings="Spectre.Console.Tests.Data.DogSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Argument Name="AGE" Position="1" Required="true" Kind="scalar" ClrType="System.Int32" />
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
<Option Short="g" Long="good-boy" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean" />
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
</Model>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--ANIMAL-->
<Command Name="animal" IsBranch="true" Settings="Spectre.Console.Tests.Data.AnimalSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
</Parameters>
<!--DOG-->
<Command Name="dog" IsBranch="false" ClrType="Spectre.Console.Tests.Data.DogCommand" Settings="Spectre.Console.Tests.Data.DogSettings">
<Parameters>
<Argument Name="AGE" Position="0" Required="true" Kind="scalar" ClrType="System.Int32" />
<Option Short="g" Long="good-boy" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean" />
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
<!--HORSE-->
<Command Name="horse" IsBranch="false" ClrType="Spectre.Console.Tests.Data.HorseCommand" Settings="Spectre.Console.Tests.Data.MammalSettings">
<Parameters>
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
</Command>
</Model>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--ANIMAL-->
<Command Name="animal" IsBranch="true" Settings="Spectre.Console.Tests.Data.AnimalSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
</Parameters>
<!--DOG-->
<Command Name="dog" IsBranch="false" ClrType="Spectre.Console.Tests.Data.DogCommand" Settings="Spectre.Console.Tests.Data.DogSettings">
<Parameters>
<Argument Name="AGE" Position="0" Required="true" Kind="scalar" ClrType="System.Int32" />
<Option Short="g" Long="good-boy" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean" />
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
</Command>
</Model>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--CMD-->
<Command Name="cmd" IsBranch="false" ClrType="Spectre.Console.Tests.Data.OptionVectorCommand" Settings="Spectre.Console.Tests.Data.OptionVectorSettings">
<Parameters>
<Option Short="" Long="bar" Value="NULL" Required="false" Kind="vector" ClrType="System.Int32[]" />
<Option Short="" Long="foo" Value="NULL" Required="false" Kind="vector" ClrType="System.String[]" />
</Parameters>
</Command>
</Model>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Model>
<!--DEFAULT COMMAND-->
<Command Name="__default_command" IsBranch="false" IsDefault="true" ClrType="Spectre.Console.Tests.Data.DogCommand" Settings="Spectre.Console.Tests.Data.DogSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Argument Name="AGE" Position="1" Required="true" Kind="scalar" ClrType="System.Int32" />
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
<Option Short="g" Long="good-boy" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean" />
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
<!--HORSE-->
<Command Name="horse" IsBranch="false" ClrType="Spectre.Console.Tests.Data.HorseCommand" Settings="Spectre.Console.Tests.Data.MammalSettings">
<Parameters>
<Argument Name="LEGS" Position="0" Required="false" Kind="scalar" ClrType="System.Int32">
<Description>The number of legs.</Description>
<Validators>
<Validator ClrType="Spectre.Console.Tests.Data.EvenNumberValidatorAttribute" Message="Animals must have an even number of legs." />
<Validator ClrType="Spectre.Console.Tests.Data.PositiveNumberValidatorAttribute" Message="Number of legs must be greater than 0." />
</Validators>
</Argument>
<Option Short="a" Long="alive,not-dead" Value="NULL" Required="false" Kind="flag" ClrType="System.Boolean">
<Description>Indicates whether or not the animal is alive.</Description>
</Option>
<Option Short="n,p" Long="name,pet-name" Value="VALUE" Required="false" Kind="scalar" ClrType="System.String" />
</Parameters>
</Command>
</Model>

View File

@ -0,0 +1,17 @@
global using System;
global using System.Collections.Generic;
global using System.ComponentModel;
global using System.Diagnostics.CodeAnalysis;
global using System.Globalization;
global using System.Linq;
global using System.Runtime.CompilerServices;
global using System.Threading.Tasks;
global using Shouldly;
global using Spectre.Console.Cli;
global using Spectre.Console.Cli.Unsafe;
global using Spectre.Console.Testing;
global using Spectre.Console.Tests.Data;
global using Spectre.Verify.Extensions;
global using VerifyTests;
global using VerifyXunit;
global using Xunit;

View File

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0;net48</TargetFrameworks>
<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('Windows'))">net6.0;net5.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\src\stylecop.json" Link="Properties/stylecop.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit" Version="1.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="1.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.6.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="Shouldly" Version="4.0.3" />
<PackageReference Include="Spectre.Verify.Extensions" Version="0.3.0" />
<PackageReference Include="Verify.Xunit" Version="9.0.0-beta.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spectre.Console.Cli\Spectre.Console.Cli.csproj" />
<ProjectReference Include="..\..\src\Spectre.Console.Testing\Spectre.Console.Testing.csproj" />
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
</Project>

Some files were not shown because too many files have changed in this diff Show More