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

@ -6,6 +6,7 @@
<DebugType>embedded</DebugType>
<MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup Label="Deterministic Build" Condition="'$(GITHUB_ACTIONS)' == 'true'">
@ -32,13 +33,13 @@
</PropertyGroup>
<ItemGroup Label="Package References">
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.0" />
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.4.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.113">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="3.0.0">

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>true</IsPackable>
<Description>A library that extends Spectre.Console with ImageSharp superpowers.</Description>
</PropertyGroup>

View File

@ -0,0 +1,14 @@
root = false
[*.cs]
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = none
# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none
# Default severity for analyzer diagnostics with category 'StyleCop.CSharp.OrderingRules'
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = none
# CA1819: Properties should not return arrays
dotnet_diagnostic.CA1819.severity = none

View File

@ -0,0 +1,92 @@
using System;
using Spectre.Console.Cli;
namespace Spectre.Console.Testing
{
public sealed class CommandAppFixture
{
private Action<CommandApp> _appConfiguration = _ => { };
private Action<IConfigurator> _configuration;
public CommandAppFixture()
{
_configuration = (_) => { };
}
public CommandAppFixture WithDefaultCommand<T>()
where T : class, ICommand
{
_appConfiguration = (app) => app.SetDefaultCommand<T>();
return this;
}
public void Configure(Action<IConfigurator> action)
{
_configuration = action;
}
public (string Message, string Output) RunAndCatch<T>(params string[] args)
where T : Exception
{
CommandContext context = null;
CommandSettings settings = null;
using var console = new FakeConsole();
var app = new CommandApp();
_appConfiguration?.Invoke(app);
app.Configure(_configuration);
app.Configure(c => c.ConfigureConsole(console));
app.Configure(c => c.SetInterceptor(new FakeCommandInterceptor((ctx, s) =>
{
context = ctx;
settings = s;
})));
try
{
app.Run(args);
}
catch (T ex)
{
var output = console.Output
.NormalizeLineEndings()
.TrimLines()
.Trim();
return (ex.Message, output);
}
throw new InvalidOperationException("No exception was thrown");
}
public (int ExitCode, string Output, CommandContext Context, CommandSettings Settings) Run(params string[] args)
{
CommandContext context = null;
CommandSettings settings = null;
using var console = new FakeConsole(width: int.MaxValue);
var app = new CommandApp();
_appConfiguration?.Invoke(app);
app.Configure(_configuration);
app.Configure(c => c.ConfigureConsole(console));
app.Configure(c => c.SetInterceptor(new FakeCommandInterceptor((ctx, s) =>
{
context = ctx;
settings = s;
})));
var result = app.Run(args);
var output = console.Output
.NormalizeLineEndings()
.TrimLines()
.Trim();
return (result, output, context, settings);
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.IO;
using System.Reflection;
namespace Spectre.Console.Tests
{
public static class EmbeddedResourceReader
{
public static Stream LoadResourceStream(string resourceName)
{
if (resourceName is null)
{
throw new ArgumentNullException(nameof(resourceName));
}
var assembly = Assembly.GetCallingAssembly();
resourceName = resourceName.ReplaceExact("/", ".");
return assembly.GetManifestResourceStream(resourceName);
}
public static Stream LoadResourceStream(Assembly assembly, string resourceName)
{
if (assembly is null)
{
throw new ArgumentNullException(nameof(assembly));
}
if (resourceName is null)
{
throw new ArgumentNullException(nameof(resourceName));
}
resourceName = resourceName.ReplaceExact("/", ".");
return assembly.GetManifestResourceStream(resourceName);
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Linq;
using Shouldly;
namespace Spectre.Console.Cli
{
public static class CommandContextExtensions
{
public static void ShouldHaveRemainingArgument(this CommandContext context, string name, string[] values)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (values == null)
{
throw new ArgumentNullException(nameof(values));
}
context.Remaining.Parsed.Contains(name).ShouldBeTrue();
context.Remaining.Parsed[name].Count().ShouldBe(values.Length);
foreach (var value in values)
{
context.Remaining.Parsed[name].ShouldContain(value);
}
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Diagnostics;
using Shouldly;
namespace Spectre.Console
{
public static class ShouldlyExtensions
{
[DebuggerStepThrough]
public static T And<T>(this T item, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
action(item);
return item;
}
[DebuggerStepThrough]
public static void As<T>(this T item, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
action(item);
}
[DebuggerStepThrough]
public static void As<T>(this object item, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
action((T)item);
}
[DebuggerStepThrough]
public static void ShouldBe<T>(this Type item)
{
item.ShouldBe(typeof(T));
}
}
}

View File

@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Spectre.Console
{
public static class StringExtensions
{
private static readonly Regex _lineNumberRegex = new Regex(":\\d+", RegexOptions.Singleline);
private static readonly Regex _filenameRegex = new Regex("\\sin\\s.*cs:nn", RegexOptions.Multiline);
public static string TrimLines(this string value)
{
if (value is null)
{
return string.Empty;
}
var result = new List<string>();
var lines = value.Split(new[] { '\n' });
foreach (var line in lines)
{
var current = line.TrimEnd();
if (string.IsNullOrWhiteSpace(current))
{
result.Add(string.Empty);
}
else
{
result.Add(current);
}
}
return string.Join("\n", result);
}
public static string NormalizeLineEndings(this string value)
{
if (value != null)
{
value = value.Replace("\r\n", "\n");
return value.Replace("\r", string.Empty);
}
return string.Empty;
}
public static string NormalizeStackTrace(this string text)
{
text = _lineNumberRegex.Replace(text, match =>
{
return ":nn";
});
return _filenameRegex.Replace(text, match =>
{
var value = match.Value;
var index = value.LastIndexOfAny(new[] { '\\', '/' });
var filename = value.Substring(index + 1, value.Length - index - 1);
return $" in /xyz/{filename}";
});
}
internal static string ReplaceExact(this string text, string oldValue, string newValue)
{
if (string.IsNullOrWhiteSpace(newValue))
{
return text;
}
#if NET5_0
return text.Replace(oldValue, newValue, StringComparison.Ordinal);
#else
return text.Replace(oldValue, newValue);
#endif
}
}
}

View File

@ -1,6 +1,6 @@
namespace Spectre.Console.Tests
{
internal static class StyleExtensions
public static class StyleExtensions
{
public static Style SetColor(this Style style, Color color, bool foreground)
{

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Xml;
namespace Spectre.Console
{
public static class XmlElementExtensions
{
public static void SetNullableAttribute(this XmlElement element, string name, string value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
element.SetAttribute(name, value ?? "NULL");
}
public static void SetNullableAttribute(this XmlElement element, string name, IEnumerable<string> values)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
if (values?.Any() != true)
{
element.SetAttribute(name, "NULL");
}
element.SetAttribute(name, string.Join(",", values));
}
public static void SetBooleanAttribute(this XmlElement element, string name, bool value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
element.SetAttribute(name, value ? "true" : "false");
}
public static void SetEnumAttribute(this XmlElement element, string name, Enum value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
var field = value.GetType().GetField(value.ToString());
var attribute = field.GetCustomAttribute<DescriptionAttribute>(false);
if (attribute == null)
{
throw new InvalidOperationException("Enum is missing description.");
}
element.SetAttribute(name, attribute.Description);
}
}
}

View File

@ -4,9 +4,9 @@ using System.IO;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console.Tests
namespace Spectre.Console.Testing
{
public sealed class TestableAnsiConsole : IDisposable, IAnsiConsole
public sealed class FakeAnsiConsole : IDisposable, IAnsiConsole
{
private readonly StringWriter _writer;
private readonly IAnsiConsole _console;
@ -18,12 +18,12 @@ namespace Spectre.Console.Tests
public int Width { get; }
public int Height => _console.Height;
public IAnsiConsoleCursor Cursor => _console.Cursor;
public TestableConsoleInput Input { get; }
public FakeConsoleInput Input { get; }
public RenderPipeline Pipeline => _console.Pipeline;
IAnsiConsoleInput IAnsiConsole.Input => Input;
public TestableAnsiConsole(
public FakeAnsiConsole(
ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes,
InteractionSupport interaction = InteractionSupport.Yes,
int width = 80)
@ -35,11 +35,11 @@ namespace Spectre.Console.Tests
ColorSystem = (ColorSystemSupport)system,
Interactive = interaction,
Out = _writer,
LinkIdentityGenerator = new TestLinkIdentityGenerator(),
LinkIdentityGenerator = new FakeLinkIdentityGenerator(1024),
});
Width = width;
Input = new TestableConsoleInput();
Input = new FakeConsoleInput();
}
public void Dispose()

View File

@ -1,6 +1,6 @@
namespace Spectre.Console.Tests
namespace Spectre.Console.Testing
{
public sealed class DummyCursor : IAnsiConsoleCursor
public sealed class FakeAnsiConsoleCursor : IAnsiConsoleCursor
{
public void Move(CursorDirection direction, int steps)
{

View File

@ -0,0 +1,20 @@
using System;
using Spectre.Console.Cli;
namespace Spectre.Console.Testing
{
public sealed class FakeCommandInterceptor : ICommandInterceptor
{
private readonly Action<CommandContext, CommandSettings> _action;
public FakeCommandInterceptor(Action<CommandContext, CommandSettings> action)
{
_action = action ?? throw new ArgumentNullException(nameof(action));
}
public void Intercept(CommandContext context, CommandSettings settings)
{
_action(context, settings);
}
}
}

View File

@ -5,14 +5,14 @@ using System.Linq;
using System.Text;
using Spectre.Console.Rendering;
namespace Spectre.Console.Tests
namespace Spectre.Console.Testing
{
public sealed class PlainConsole : IAnsiConsole, IDisposable
public sealed class FakeConsole : IAnsiConsole, IDisposable
{
public Capabilities Capabilities { get; }
public Encoding Encoding { get; }
public IAnsiConsoleCursor Cursor => new DummyCursor();
public TestableConsoleInput Input { get; }
public IAnsiConsoleCursor Cursor => new FakeAnsiConsoleCursor();
public FakeConsoleInput Input { get; }
public int Width { get; }
public int Height { get; }
@ -29,7 +29,7 @@ namespace Spectre.Console.Tests
public string Output => Writer.ToString();
public IReadOnlyList<string> Lines => Output.TrimEnd('\n').Split(new char[] { '\n' });
public PlainConsole(
public FakeConsole(
int width = 80, int height = 9000, Encoding encoding = null,
bool supportsAnsi = true, ColorSystem colorSystem = ColorSystem.Standard,
bool legacyConsole = false, bool interactive = true)
@ -39,7 +39,7 @@ namespace Spectre.Console.Tests
Width = width;
Height = height;
Writer = new StringWriter();
Input = new TestableConsoleInput();
Input = new FakeConsoleInput();
Pipeline = new RenderPipeline();
}

View File

@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
namespace Spectre.Console.Tests
namespace Spectre.Console.Testing
{
public sealed class TestableConsoleInput : IAnsiConsoleInput
public sealed class FakeConsoleInput : IAnsiConsoleInput
{
private readonly Queue<ConsoleKeyInfo> _input;
public TestableConsoleInput()
public FakeConsoleInput()
{
_input = new Queue<ConsoleKeyInfo>();
}

View File

@ -0,0 +1,17 @@
namespace Spectre.Console.Testing
{
public sealed class FakeLinkIdentityGenerator : ILinkIdentityGenerator
{
private readonly int _linkId;
public FakeLinkIdentityGenerator(int linkId)
{
_linkId = linkId;
}
public int GenerateId(string link, string text)
{
return _linkId;
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using Spectre.Console.Cli;
namespace Spectre.Console.Testing
{
public sealed class FakeTypeRegistrar : ITypeRegistrar
{
private readonly ITypeResolver _resolver;
public Dictionary<Type, List<Type>> Registrations { get; }
public Dictionary<Type, List<object>> Instances { get; }
public FakeTypeRegistrar(ITypeResolver resolver = null)
{
_resolver = resolver;
Registrations = new Dictionary<Type, List<Type>>();
Instances = new Dictionary<Type, List<object>>();
}
public void Register(Type service, Type implementation)
{
if (!Registrations.ContainsKey(service))
{
Registrations.Add(service, new List<Type> { implementation });
}
else
{
Registrations[service].Add(implementation);
}
}
public void RegisterInstance(Type service, object implementation)
{
if (!Instances.ContainsKey(service))
{
Instances.Add(service, new List<object> { implementation });
}
}
public ITypeResolver Build()
{
return _resolver;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using Spectre.Console.Cli;
namespace Spectre.Console.Testing
{
public sealed class FakeTypeResolver : ITypeResolver
{
private readonly IDictionary<Type, object> _lookup;
public FakeTypeResolver()
{
_lookup = new Dictionary<Type, object>();
}
public void Register<T>(T instance)
{
_lookup[typeof(T)] = instance;
}
public object Resolve(Type type)
{
if (_lookup.TryGetValue(type, out var value))
{
return value;
}
return Activator.CreateInstance(type);
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Shouldly" Version="4.0.3" />
<PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
namespace Spectre.Console.Testing
{
public sealed class DummySpinner1 : Spinner
{
public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
public override bool IsUnicode => true;
public override IReadOnlyList<string> Frames => new List<string> { "*", };
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
namespace Spectre.Console.Testing
{
public sealed class DummySpinner2 : Spinner
{
public override TimeSpan Interval => TimeSpan.FromMilliseconds(100);
public override bool IsUnicode => true;
public override IReadOnlyList<string> Frames => new List<string> { "-", };
}
}

View File

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

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}).");
}
}
}

View File

@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Xunit.Sdk;
namespace Spectre.Console.Tests
{
public sealed class EmbeddedResourceDataAttribute : DataAttribute
{
private readonly string _args;
public EmbeddedResourceDataAttribute(string args)
{
_args = args ?? throw new ArgumentNullException(nameof(args));
}
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
var result = new object[1];
result[0] = ReadManifestData(_args);
return new[] { result };
}
public static string ReadManifestData(string resourceName)
{
if (resourceName is null)
{
throw new ArgumentNullException(nameof(resourceName));
}
using (var stream = ResourceReader.LoadResourceStream(resourceName))
{
if (stream == null)
{
throw new InvalidOperationException("Could not load manifest resource stream.");
}
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd().NormalizeLineEndings();
}
}
}
}
}

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,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,13 @@
USAGE:
myapp <TEETH> [LEGS] [OPTIONS]
ARGUMENTS:
[LEGS] The number of legs
<TEETH> The number of teeth the lion has
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 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,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,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,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,16 @@
USAGE:
myapp <TEETH> [LEGS] [OPTIONS]
EXAMPLES:
myapp 12 -c 3
ARGUMENTS:
[LEGS] The number of legs
<TEETH> The number of teeth the lion has
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,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,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: 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,4 @@
Error: Option does not have a name.
dog -
^ Did you forget the option name?

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 option 'unknown'.
dog --unknown
^^^^^^^^^ 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,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,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.
Multiple values are not supported.
<FOO> <BAR>
^^^^^ Too many values

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