Add Spectre.Cli to Spectre.Console

* Renames Spectre.Cli to Spectre.Console.Cli.
* Now uses Verify with Spectre.Console.Cli tests.
* Removes some duplicate definitions.

Closes #168
This commit is contained in:
Patrik Svensson
2020-12-23 10:41:29 +01:00
committed by Patrik Svensson
parent 0bbf9b81a9
commit 0ae419326d
361 changed files with 13934 additions and 604 deletions

View File

@ -0,0 +1,49 @@
using System;
using System.Linq;
using Spectre.Console.Cli;
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,13 @@
using Spectre.Console.Cli;
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,36 @@
using System.ComponentModel;
using System.Linq;
using Spectre.Console.Cli;
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,12 @@
using Spectre.Console.Cli;
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,13 @@
using Spectre.Console.Cli;
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,14 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,15 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,22 @@
using System;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class InterceptingCommand<TSettings> : Command<TSettings>
where TSettings : CommandSettings
{
private readonly Action<CommandContext, TSettings> _action;
public InterceptingCommand(Action<CommandContext, TSettings> action)
{
_action = action ?? throw new ArgumentNullException(nameof(action));
}
public override int Execute(CommandContext context, TSettings settings)
{
_action(context, settings);
return 0;
}
}
}

View File

@ -0,0 +1,12 @@
using Spectre.Console.Cli;
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,14 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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 @@
using Spectre.Console.Cli;
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,17 @@
using System;
using Spectre.Console.Cli;
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,18 @@
using System.ComponentModel;
using System.Globalization;
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,18 @@
using System.ComponentModel;
using System.Globalization;
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,18 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,12 @@
using System.Diagnostics.CodeAnalysis;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public class ArgumentVectorSettings : CommandSettings
{
[CommandArgument(0, "<Foos>")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public string[] Foo { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,15 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,23 @@
using Spectre.Console.Cli;
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,8 @@
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class EmptySettings : CommandSettings
{
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,12 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,10 @@
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class InvalidSettings : CommandSettings
{
[CommandOption("-f|--foo [BAR]")]
public string Value { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System.ComponentModel;
using Spectre.Console.Cli;
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,10 @@
using Spectre.Console.Cli;
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,26 @@
using System.Diagnostics.CodeAnalysis;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public class MultipleArgumentVectorSettings : CommandSettings
{
[CommandArgument(0, "<Foos>")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public string[] Foo { get; set; }
[CommandArgument(0, "<Bars>")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public string[] Bar { get; set; }
}
public class MultipleArgumentVectorSpecifiedFirstSettings : CommandSettings
{
[CommandArgument(0, "<Foos>")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public string[] Foo { get; set; }
[CommandArgument(1, "<Bar>")]
public string Bar { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System.Diagnostics.CodeAnalysis;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public class OptionVectorSettings : CommandSettings
{
[CommandOption("--foo")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public string[] Foo { get; set; }
[CommandOption("--bar")]
[SuppressMessage("Performance", "CA1819:Properties should not return arrays")]
public int[] Bar { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System.ComponentModel;
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class OptionalArgumentWithDefaultValueSettings : CommandSettings
{
[CommandArgument(0, "[GREETING]")]
[DefaultValue("Hello World")]
public string Greeting { get; set; }
}
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,10 @@
using Spectre.Console.Cli;
namespace Spectre.Console.Tests.Data
{
public sealed class StringOptionSettings : CommandSettings
{
[CommandOption("-f|--foo")]
public string Foo { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using System;
using Spectre.Console.Cli;
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(ICommandParameterInfo info, object value)
{
if (value is int integer)
{
if (integer % 2 == 0)
{
return ValidationResult.Success();
}
return ValidationResult.Error($"Number is not even ({info?.PropertyName}).");
}
throw new InvalidOperationException($"Parameter is not a number ({info?.PropertyName}).");
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using Spectre.Console.Cli;
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(ICommandParameterInfo info, object value)
{
if (value is int integer)
{
if (integer > 0)
{
return ValidationResult.Success();
}
return ValidationResult.Error($"Number is not greater than 0 ({info?.PropertyName}).");
}
throw new InvalidOperationException($"Parameter is not a number ({info?.PropertyName}).");
}
}
}