Add global usings (#668)

* Use global usings

* Fix namespace declarations for test projects
This commit is contained in:
Patrik Svensson
2021-12-23 16:50:31 +01:00
committed by GitHub
parent eb6a9d8d04
commit 52c1d9122b
514 changed files with 10659 additions and 12441 deletions

View File

@ -1,97 +1,88 @@
using System.Threading.Tasks;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Spectre.Verify.Extensions;
using VerifyXunit;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
namespace Spectre.Console.Tests.Unit.Cli.Annotations
[ExpectationPath("Cli/Arguments")]
public sealed partial class CommandArgumentAttributeTests
{
[ExpectationPath("Cli/Arguments")]
public sealed partial class CommandArgumentAttributeTests
[UsesVerify]
public sealed class ArgumentCannotContainOptions
{
[UsesVerify]
public sealed class ArgumentCannotContainOptions
public sealed class Settings : CommandSettings
{
public sealed class Settings : CommandSettings
{
[CommandArgument(0, "--foo <BAR>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("ArgumentCannotContainOptions")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
return Verifier.Verify(result);
}
[CommandArgument(0, "--foo <BAR>")]
public string Foo { get; set; }
}
[UsesVerify]
public sealed class MultipleValuesAreNotSupported
[Fact]
[Expectation("ArgumentCannotContainOptions")]
public Task Should_Return_Correct_Text()
{
public sealed class Settings : CommandSettings
{
[CommandArgument(0, "<FOO> <BAR>")]
public string Foo { get; set; }
}
// Given, When
var result = Fixture.Run<Settings>();
[Fact]
[Expectation("MultipleValuesAreNotSupported")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
return Verifier.Verify(result);
}
}
// Then
return Verifier.Verify(result);
}
[UsesVerify]
public sealed class MultipleValuesAreNotSupported
{
public sealed class Settings : CommandSettings
{
[CommandArgument(0, "<FOO> <BAR>")]
public string Foo { get; set; }
}
[UsesVerify]
public sealed class ValuesMustHaveName
[Fact]
[Expectation("MultipleValuesAreNotSupported")]
public Task Should_Return_Correct_Text()
{
public sealed class Settings : CommandSettings
{
[CommandArgument(0, "<>")]
public string Foo { get; set; }
}
// Given, When
var result = Fixture.Run<Settings>();
[Fact]
[Expectation("ValuesMustHaveName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
return Verifier.Verify(result);
}
}
// Then
return Verifier.Verify(result);
}
[UsesVerify]
public sealed class ValuesMustHaveName
{
public sealed class Settings : CommandSettings
{
[CommandArgument(0, "<>")]
public string Foo { get; set; }
}
private static class Fixture
[Fact]
[Expectation("ValuesMustHaveName")]
public Task Should_Return_Correct_Text()
{
public static string Run<TSettings>(params string[] args)
where TSettings : CommandSettings
{
using (var writer = new TestConsole())
{
var app = new CommandApp();
app.Configure(c => c.ConfigureConsole(writer));
app.Configure(c => c.AddCommand<GenericCommand<TSettings>>("foo"));
app.Run(args);
// Given, When
var result = Fixture.Run<Settings>();
return writer.Output
.NormalizeLineEndings()
.TrimLines()
.Trim();
}
// Then
return Verifier.Verify(result);
}
}
private static class Fixture
{
public static string Run<TSettings>(params string[] args)
where TSettings : CommandSettings
{
using (var writer = new TestConsole())
{
var app = new CommandApp();
app.Configure(c => c.ConfigureConsole(writer));
app.Configure(c => c.AddCommand<GenericCommand<TSettings>>("foo"));
app.Run(args);
return writer.Output
.NormalizeLineEndings()
.TrimLines()
.Trim();
}
}
}
}
}

View File

@ -1,64 +1,59 @@
using Shouldly;
using Spectre.Console.Cli;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
namespace Spectre.Console.Tests.Unit.Cli.Annotations
public sealed partial class CommandArgumentAttributeTests
{
public sealed partial class CommandArgumentAttributeTests
[Fact]
public void Should_Not_Contain_Options()
{
[Fact]
public void Should_Not_Contain_Options()
{
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, "--foo <BAR>"));
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, "--foo <BAR>"));
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Arguments can not contain options."));
}
[Theory]
[InlineData("<FOO> <BAR>")]
[InlineData("[FOO] [BAR]")]
[InlineData("[FOO] <BAR>")]
[InlineData("<FOO> [BAR]")]
public void Should_Not_Contain_Multiple_Value_Names(string template)
{
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Multiple values are not supported."));
}
[Theory]
[InlineData("<>")]
[InlineData("[]")]
public void Should_Not_Contain_Empty_Value_Name(string template)
{
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Values without name are not allowed."));
}
[Theory]
[InlineData("<FOO>", true)]
[InlineData("[FOO]", false)]
public void Should_Parse_Valid_Options(string template, bool required)
{
// Given, When
var result = new CommandArgumentAttribute(0, template);
// Then
result.ValueName.ShouldBe("FOO");
result.IsRequired.ShouldBe(required);
}
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Arguments can not contain options."));
}
}
[Theory]
[InlineData("<FOO> <BAR>")]
[InlineData("[FOO] [BAR]")]
[InlineData("[FOO] <BAR>")]
[InlineData("<FOO> [BAR]")]
public void Should_Not_Contain_Multiple_Value_Names(string template)
{
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Multiple values are not supported."));
}
[Theory]
[InlineData("<>")]
[InlineData("[]")]
public void Should_Not_Contain_Empty_Value_Name(string template)
{
// Given, When
var result = Record.Exception(() => new CommandArgumentAttribute(0, template));
// Then
result.ShouldNotBe(null);
result.ShouldBeOfType<CommandTemplateException>().And(exception =>
exception.Message.ShouldBe("Values without name are not allowed."));
}
[Theory]
[InlineData("<FOO>", true)]
[InlineData("[FOO]", false)]
public void Should_Parse_Valid_Options(string template, bool required)
{
// Given, When
var result = new CommandArgumentAttribute(0, template);
// Then
result.ValueName.ShouldBe("FOO");
result.IsRequired.ShouldBe(required);
}
}

View File

@ -1,250 +1,240 @@
using System.Threading.Tasks;
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Spectre.Verify.Extensions;
using VerifyXunit;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
namespace Spectre.Console.Tests.Unit.Cli.Annotations
[ExpectationPath("Cli/Arguments")]
public sealed partial class CommandOptionAttributeTests
{
[ExpectationPath("Cli/Arguments")]
public sealed partial class CommandOptionAttributeTests
[UsesVerify]
public sealed class UnexpectedCharacter
{
[UsesVerify]
public sealed class UnexpectedCharacter
public sealed class Settings : CommandSettings
{
public sealed class Settings : CommandSettings
{
[CommandOption("<FOO> $ <BAR>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("UnexpectedCharacter")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered unexpected character '$'.");
return Verifier.Verify(result.Output);
}
[CommandOption("<FOO> $ <BAR>")]
public string Foo { get; set; }
}
[UsesVerify]
public sealed class UnterminatedValueName
[Fact]
[Expectation("UnexpectedCharacter")]
public Task Should_Return_Correct_Text()
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-f <BAR")]
public string Foo { get; set; }
}
// Given, When
var result = Fixture.Run<Settings>();
[Fact]
[Expectation("UnterminatedValueName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered unterminated value name 'BAR'.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class OptionsMustHaveName
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-")]
public string Foo { get; set; }
}
[Fact]
[Expectation("OptionsMustHaveName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Options without name are not allowed.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class OptionNamesCannotStartWithDigit
{
public sealed class Settings : CommandSettings
{
[CommandOption("--1foo")]
public string Foo { get; set; }
}
[Fact]
[Expectation("OptionNamesCannotStartWithDigit")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Option names cannot start with a digit.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class InvalidCharacterInOptionName
{
public sealed class Settings : CommandSettings
{
[CommandOption("--f$oo")]
public string Foo { get; set; }
}
[Fact]
[Expectation("InvalidCharacterInOptionName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered invalid character '$' in option name.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class LongOptionMustHaveMoreThanOneCharacter
{
public sealed class Settings : CommandSettings
{
[CommandOption("--f")]
public string Foo { get; set; }
}
[Fact]
[Expectation("LongOptionMustHaveMoreThanOneCharacter")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Long option names must consist of more than one character.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class ShortOptionMustOnlyBeOneCharacter
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-bar")]
public string Foo { get; set; }
}
[Fact]
[Expectation("ShortOptionMustOnlyBeOneCharacter")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Short option names can not be longer than one character.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class MultipleOptionValuesAreNotSupported
{
public sealed class Settings : CommandSettings
{
[CommandOption("-f|--foo <FOO> <BAR>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("MultipleOptionValuesAreNotSupported")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Multiple option values are not supported.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class InvalidCharacterInValueName
{
public sealed class Settings : CommandSettings
{
[CommandOption("-f|--foo <F$OO>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("InvalidCharacterInValueName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered invalid character '$' in value name.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class MissingLongAndShortName
{
public sealed class Settings : CommandSettings
{
[CommandOption("<FOO>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("MissingLongAndShortName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("No long or short name for option has been specified.");
return Verifier.Verify(result.Output);
}
}
private static class Fixture
{
public static CommandAppFailure Run<TSettings>(params string[] args)
where TSettings : CommandSettings
{
var app = new CommandAppTester();
app.Configure(c =>
{
c.AddCommand<GenericCommand<TSettings>>("foo");
});
return app.RunAndCatch<CommandTemplateException>(args);
}
// Then
result.Exception.Message.ShouldBe("Encountered unexpected character '$'.");
return Verifier.Verify(result.Output);
}
}
}
[UsesVerify]
public sealed class UnterminatedValueName
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-f <BAR")]
public string Foo { get; set; }
}
[Fact]
[Expectation("UnterminatedValueName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered unterminated value name 'BAR'.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class OptionsMustHaveName
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-")]
public string Foo { get; set; }
}
[Fact]
[Expectation("OptionsMustHaveName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Options without name are not allowed.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class OptionNamesCannotStartWithDigit
{
public sealed class Settings : CommandSettings
{
[CommandOption("--1foo")]
public string Foo { get; set; }
}
[Fact]
[Expectation("OptionNamesCannotStartWithDigit")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Option names cannot start with a digit.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class InvalidCharacterInOptionName
{
public sealed class Settings : CommandSettings
{
[CommandOption("--f$oo")]
public string Foo { get; set; }
}
[Fact]
[Expectation("InvalidCharacterInOptionName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered invalid character '$' in option name.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class LongOptionMustHaveMoreThanOneCharacter
{
public sealed class Settings : CommandSettings
{
[CommandOption("--f")]
public string Foo { get; set; }
}
[Fact]
[Expectation("LongOptionMustHaveMoreThanOneCharacter")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Long option names must consist of more than one character.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class ShortOptionMustOnlyBeOneCharacter
{
public sealed class Settings : CommandSettings
{
[CommandOption("--foo|-bar")]
public string Foo { get; set; }
}
[Fact]
[Expectation("ShortOptionMustOnlyBeOneCharacter")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Short option names can not be longer than one character.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class MultipleOptionValuesAreNotSupported
{
public sealed class Settings : CommandSettings
{
[CommandOption("-f|--foo <FOO> <BAR>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("MultipleOptionValuesAreNotSupported")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Multiple option values are not supported.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class InvalidCharacterInValueName
{
public sealed class Settings : CommandSettings
{
[CommandOption("-f|--foo <F$OO>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("InvalidCharacterInValueName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("Encountered invalid character '$' in value name.");
return Verifier.Verify(result.Output);
}
}
[UsesVerify]
public sealed class MissingLongAndShortName
{
public sealed class Settings : CommandSettings
{
[CommandOption("<FOO>")]
public string Foo { get; set; }
}
[Fact]
[Expectation("MissingLongAndShortName")]
public Task Should_Return_Correct_Text()
{
// Given, When
var result = Fixture.Run<Settings>();
// Then
result.Exception.Message.ShouldBe("No long or short name for option has been specified.");
return Verifier.Verify(result.Output);
}
}
private static class Fixture
{
public static CommandAppFailure Run<TSettings>(params string[] args)
where TSettings : CommandSettings
{
var app = new CommandAppTester();
app.Configure(c =>
{
c.AddCommand<GenericCommand<TSettings>>("foo");
});
return app.RunAndCatch<CommandTemplateException>(args);
}
}
}

View File

@ -1,217 +1,212 @@
using Shouldly;
using Spectre.Console.Cli;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli.Annotations;
namespace Spectre.Console.Tests.Unit.Cli.Annotations
public sealed partial class CommandOptionAttributeTests
{
public sealed partial class CommandOptionAttributeTests
[Fact]
public void Should_Parse_Short_Name_Correctly()
{
[Fact]
public void Should_Parse_Short_Name_Correctly()
{
// Given, When
var option = new CommandOptionAttribute("-o|--option <VALUE>");
// Given, When
var option = new CommandOptionAttribute("-o|--option <VALUE>");
// Then
option.ShortNames.ShouldContain("o");
}
[Fact]
public void Should_Parse_Long_Name_Correctly()
{
// Given, When
var option = new CommandOptionAttribute("-o|--option <VALUE>");
// Then
option.LongNames.ShouldContain("option");
}
[Theory]
[InlineData("<VALUE>")]
public void Should_Parse_Value_Correctly(string value)
{
// Given, When
var option = new CommandOptionAttribute($"-o|--option {value}");
// Then
option.ValueName.ShouldBe("VALUE");
}
[Fact]
public void Should_Parse_Only_Short_Name()
{
// Given, When
var option = new CommandOptionAttribute("-o");
// Then
option.ShortNames.ShouldContain("o");
}
[Fact]
public void Should_Parse_Only_Long_Name()
{
// Given, When
var option = new CommandOptionAttribute("--option");
// Then
option.LongNames.ShouldContain("option");
}
[Theory]
[InlineData("")]
[InlineData("<VALUE>")]
public void Should_Throw_If_Template_Is_Empty(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("No long or short name for option has been specified."));
}
[Theory]
[InlineData("--bar|-foo")]
[InlineData("--bar|-f-b")]
public void Should_Throw_If_Short_Name_Is_Invalid(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Short option names can not be longer than one character."));
}
[Theory]
[InlineData("--o")]
public void Should_Throw_If_Long_Name_Is_Invalid(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Long option names must consist of more than one character."));
}
[Theory]
[InlineData("-")]
[InlineData("--")]
public void Should_Throw_If_Option_Have_No_Name(string template)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(template));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Options without name are not allowed."));
}
[Theory]
[InlineData("--foo|-foo[b", '[')]
[InlineData("--foo|-f€b", '€')]
[InlineData("--foo|-foo@b", '@')]
public void Should_Throw_If_Option_Contains_Invalid_Name(string template, char invalid)
{
// Given, When
var result = Record.Exception(() => new CommandOptionAttribute(template));
// Then
result.ShouldBeOfType<CommandTemplateException>().And(e =>
{
e.Message.ShouldBe($"Encountered invalid character '{invalid}' in option name.");
e.Template.ShouldBe(template);
});
}
[Theory]
[InlineData("--foo <HELLO-WORLD>", "HELLO-WORLD")]
[InlineData("--foo <HELLO_WORLD>", "HELLO_WORLD")]
public void Should_Accept_Dash_And_Underscore_In_Value_Name(string template, string name)
{
// Given, When
var result = new CommandOptionAttribute(template);
// Then
result.ValueName.ShouldBe(name);
}
[Theory]
[InlineData("--foo|-1")]
public void Should_Throw_If_First_Letter_Of_An_Option_Name_Is_A_Digit(string template)
{
// Given, When
var result = Record.Exception(() => new CommandOptionAttribute(template));
// Then
result.ShouldBeOfType<CommandTemplateException>().And(e =>
{
e.Message.ShouldBe("Option names cannot start with a digit.");
e.Template.ShouldBe(template);
});
}
[Fact]
public void Multiple_Short_Options_Are_Supported()
{
// Given, When
var result = new CommandOptionAttribute("-f|-b");
// Then
result.ShortNames.Count.ShouldBe(2);
result.ShortNames.ShouldContain("f");
result.ShortNames.ShouldContain("b");
}
[Fact]
public void Multiple_Long_Options_Are_Supported()
{
// Given, When
var result = new CommandOptionAttribute("--foo|--bar");
// Then
result.LongNames.Count.ShouldBe(2);
result.LongNames.ShouldContain("foo");
result.LongNames.ShouldContain("bar");
}
[Theory]
[InlineData("-f|--foo <BAR>")]
[InlineData("--foo|-f <BAR>")]
[InlineData("<BAR> --foo|-f")]
[InlineData("<BAR> -f|--foo")]
[InlineData("-f <BAR> --foo")]
[InlineData("--foo <BAR> -f")]
public void Template_Parts_Can_Appear_In_Any_Order(string template)
{
// Given, When
var result = new CommandOptionAttribute(template);
// Then
result.LongNames.ShouldContain("foo");
result.ShortNames.ShouldContain("f");
result.ValueName.ShouldBe("BAR");
}
[Fact]
public void Is_Not_Hidden_From_Help_By_Default()
{
// Given, When
var result = new CommandOptionAttribute("--foo");
// Then
result.IsHidden.ShouldBeFalse();
}
[Fact]
public void Can_Indicate_That_It_Must_Be_Hidden_From_Help_Text()
{
// Given, When
var result = new CommandOptionAttribute("--foo") { IsHidden = true };
// Then
result.IsHidden.ShouldBeTrue();
}
// Then
option.ShortNames.ShouldContain("o");
}
}
[Fact]
public void Should_Parse_Long_Name_Correctly()
{
// Given, When
var option = new CommandOptionAttribute("-o|--option <VALUE>");
// Then
option.LongNames.ShouldContain("option");
}
[Theory]
[InlineData("<VALUE>")]
public void Should_Parse_Value_Correctly(string value)
{
// Given, When
var option = new CommandOptionAttribute($"-o|--option {value}");
// Then
option.ValueName.ShouldBe("VALUE");
}
[Fact]
public void Should_Parse_Only_Short_Name()
{
// Given, When
var option = new CommandOptionAttribute("-o");
// Then
option.ShortNames.ShouldContain("o");
}
[Fact]
public void Should_Parse_Only_Long_Name()
{
// Given, When
var option = new CommandOptionAttribute("--option");
// Then
option.LongNames.ShouldContain("option");
}
[Theory]
[InlineData("")]
[InlineData("<VALUE>")]
public void Should_Throw_If_Template_Is_Empty(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("No long or short name for option has been specified."));
}
[Theory]
[InlineData("--bar|-foo")]
[InlineData("--bar|-f-b")]
public void Should_Throw_If_Short_Name_Is_Invalid(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Short option names can not be longer than one character."));
}
[Theory]
[InlineData("--o")]
public void Should_Throw_If_Long_Name_Is_Invalid(string value)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(value));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Long option names must consist of more than one character."));
}
[Theory]
[InlineData("-")]
[InlineData("--")]
public void Should_Throw_If_Option_Have_No_Name(string template)
{
// Given, When
var option = Record.Exception(() => new CommandOptionAttribute(template));
// Then
option.ShouldBeOfType<CommandTemplateException>().And(e =>
e.Message.ShouldBe("Options without name are not allowed."));
}
[Theory]
[InlineData("--foo|-foo[b", '[')]
[InlineData("--foo|-f€b", '€')]
[InlineData("--foo|-foo@b", '@')]
public void Should_Throw_If_Option_Contains_Invalid_Name(string template, char invalid)
{
// Given, When
var result = Record.Exception(() => new CommandOptionAttribute(template));
// Then
result.ShouldBeOfType<CommandTemplateException>().And(e =>
{
e.Message.ShouldBe($"Encountered invalid character '{invalid}' in option name.");
e.Template.ShouldBe(template);
});
}
[Theory]
[InlineData("--foo <HELLO-WORLD>", "HELLO-WORLD")]
[InlineData("--foo <HELLO_WORLD>", "HELLO_WORLD")]
public void Should_Accept_Dash_And_Underscore_In_Value_Name(string template, string name)
{
// Given, When
var result = new CommandOptionAttribute(template);
// Then
result.ValueName.ShouldBe(name);
}
[Theory]
[InlineData("--foo|-1")]
public void Should_Throw_If_First_Letter_Of_An_Option_Name_Is_A_Digit(string template)
{
// Given, When
var result = Record.Exception(() => new CommandOptionAttribute(template));
// Then
result.ShouldBeOfType<CommandTemplateException>().And(e =>
{
e.Message.ShouldBe("Option names cannot start with a digit.");
e.Template.ShouldBe(template);
});
}
[Fact]
public void Multiple_Short_Options_Are_Supported()
{
// Given, When
var result = new CommandOptionAttribute("-f|-b");
// Then
result.ShortNames.Count.ShouldBe(2);
result.ShortNames.ShouldContain("f");
result.ShortNames.ShouldContain("b");
}
[Fact]
public void Multiple_Long_Options_Are_Supported()
{
// Given, When
var result = new CommandOptionAttribute("--foo|--bar");
// Then
result.LongNames.Count.ShouldBe(2);
result.LongNames.ShouldContain("foo");
result.LongNames.ShouldContain("bar");
}
[Theory]
[InlineData("-f|--foo <BAR>")]
[InlineData("--foo|-f <BAR>")]
[InlineData("<BAR> --foo|-f")]
[InlineData("<BAR> -f|--foo")]
[InlineData("-f <BAR> --foo")]
[InlineData("--foo <BAR> -f")]
public void Template_Parts_Can_Appear_In_Any_Order(string template)
{
// Given, When
var result = new CommandOptionAttribute(template);
// Then
result.LongNames.ShouldContain("foo");
result.ShortNames.ShouldContain("f");
result.ValueName.ShouldBe("BAR");
}
[Fact]
public void Is_Not_Hidden_From_Help_By_Default()
{
// Given, When
var result = new CommandOptionAttribute("--foo");
// Then
result.IsHidden.ShouldBeFalse();
}
[Fact]
public void Can_Indicate_That_It_Must_Be_Hidden_From_Help_Text()
{
// Given, When
var result = new CommandOptionAttribute("--foo") { IsHidden = true };
// Then
result.IsHidden.ShouldBeTrue();
}
}

View File

@ -1,110 +1,104 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public class NullableSettings : CommandSettings
{
public class NullableSettings : CommandSettings
public NullableSettings(bool? detailed, string[] extra)
{
public NullableSettings(bool? detailed, string[] extra)
{
Detailed = detailed;
Extra = extra;
}
[CommandOption("-d")]
public bool? Detailed { get; }
[CommandArgument(0, "[extra]")]
public string[] Extra { get; }
Detailed = detailed;
Extra = extra;
}
public class NullableWithInitSettings : CommandSettings
{
[CommandOption("-d")]
public bool? Detailed { get; init; }
[CommandOption("-d")]
public bool? Detailed { get; }
[CommandArgument(0, "[extra]")]
public string[] Extra { get; init; }
}
public class NullableCommand : Command<NullableSettings>
{
public override int Execute(CommandContext context, NullableSettings settings) => 0;
}
public class NullableWithInitCommand : Command<NullableWithInitSettings>
{
public override int Execute(CommandContext context, NullableWithInitSettings settings) => 0;
}
[Fact]
public void Should_Populate_Nullable_Objects_In_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableCommand>("null");
});
// When
var result = fixture.Run("null");
// Then
result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
{
settings.Detailed.ShouldBeNull();
settings.Extra.ShouldBeNull();
});
}
[Fact]
public void Should_Populate_Nullable_Objects_With_Init_In_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableWithInitCommand>("null");
});
// When
var result = fixture.Run("null");
// Then
result.Settings.ShouldBeOfType<NullableWithInitSettings>().And(settings =>
{
settings.Detailed.ShouldBeNull();
settings.Extra.ShouldBeNull();
});
}
[Fact]
public void Should_Populate_Regular_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableCommand>("null");
});
// When
var result = fixture.Run("null", "-d", "true", "first-item");
// Then
result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
{
settings.Detailed.ShouldBe(true);
settings.Extra.ShouldBe(new[] { "first-item" });
});
}
[CommandArgument(0, "[extra]")]
public string[] Extra { get; }
}
}
public class NullableWithInitSettings : CommandSettings
{
[CommandOption("-d")]
public bool? Detailed { get; init; }
[CommandArgument(0, "[extra]")]
public string[] Extra { get; init; }
}
public class NullableCommand : Command<NullableSettings>
{
public override int Execute(CommandContext context, NullableSettings settings) => 0;
}
public class NullableWithInitCommand : Command<NullableWithInitSettings>
{
public override int Execute(CommandContext context, NullableWithInitSettings settings) => 0;
}
[Fact]
public void Should_Populate_Nullable_Objects_In_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableCommand>("null");
});
// When
var result = fixture.Run("null");
// Then
result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
{
settings.Detailed.ShouldBeNull();
settings.Extra.ShouldBeNull();
});
}
[Fact]
public void Should_Populate_Nullable_Objects_With_Init_In_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableWithInitCommand>("null");
});
// When
var result = fixture.Run("null");
// Then
result.Settings.ShouldBeOfType<NullableWithInitSettings>().And(settings =>
{
settings.Detailed.ShouldBeNull();
settings.Extra.ShouldBeNull();
});
}
[Fact]
public void Should_Populate_Regular_Settings()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NullableCommand>("null");
});
// When
var result = fixture.Run("null", "-d", "true", "first-item");
// Then
result.Settings.ShouldBeOfType<NullableSettings>().And(settings =>
{
settings.Detailed.ShouldBe(true);
settings.Extra.ShouldBe(new[] { "first-item" });
});
}
}

View File

@ -1,100 +1,92 @@
using System;
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Exception_Handling
{
public sealed class Exception_Handling
[Fact]
public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
{
[Fact]
public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
});
// When
var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
// When
var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
// Then
result.ExitCode.ShouldBe(-1);
}
// Then
result.ExitCode.ShouldBe(-1);
}
[Fact]
public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
[Fact]
public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.AddCommand<ThrowingCommand>("throw");
});
config.AddCommand<ThrowingCommand>("throw");
});
// When
var result = app.Run(new[] { "throw" });
// When
var result = app.Run(new[] { "throw" });
// Then
result.ExitCode.ShouldBe(-1);
}
// Then
result.ExitCode.ShouldBe(-1);
}
[Fact]
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Action()
[Fact]
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Action()
{
// Given
var exceptionHandled = false;
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var exceptionHandled = false;
var app = new CommandAppTester();
app.Configure(config =>
config.AddCommand<ThrowingCommand>("throw");
config.SetExceptionHandler(_ =>
{
config.AddCommand<ThrowingCommand>("throw");
config.SetExceptionHandler(_ =>
{
exceptionHandled = true;
});
exceptionHandled = true;
});
});
// When
var result = app.Run(new[] { "throw" });
// When
var result = app.Run(new[] { "throw" });
// Then
result.ExitCode.ShouldBe(-1);
exceptionHandled.ShouldBeTrue();
}
// Then
result.ExitCode.ShouldBe(-1);
exceptionHandled.ShouldBeTrue();
}
[Fact]
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Function()
[Fact]
public void Should_Handle_Exceptions_If_ExceptionHandler_Is_Set_Using_Function()
{
// Given
var exceptionHandled = false;
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var exceptionHandled = false;
var app = new CommandAppTester();
app.Configure(config =>
config.AddCommand<ThrowingCommand>("throw");
config.SetExceptionHandler(_ =>
{
config.AddCommand<ThrowingCommand>("throw");
config.SetExceptionHandler(_ =>
{
exceptionHandled = true;
return -99;
});
exceptionHandled = true;
return -99;
});
});
// When
var result = app.Run(new[] { "throw" });
// When
var result = app.Run(new[] { "throw" });
// Then
result.ExitCode.ShouldBe(-99);
exceptionHandled.ShouldBeTrue();
}
// Then
result.ExitCode.ShouldBe(-99);
exceptionHandled.ShouldBeTrue();
}
}
}
}

View File

@ -1,223 +1,214 @@
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class FlagValues
{
public sealed class FlagValues
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettings : CommandSettings
{
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettings : CommandSettings
[CommandOption("--serve [PORT]")]
public FlagValue<int> Serve { get; set; }
}
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithNullableValueType : CommandSettings
{
[CommandOption("--serve [PORT]")]
public FlagValue<int?> Serve { get; set; }
}
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithOptionalOptionButNoFlagValue : CommandSettings
{
[CommandOption("--serve [PORT]")]
public int Serve { get; set; }
}
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithDefaultValue : CommandSettings
{
[CommandOption("--serve [PORT]")]
[DefaultValue(987)]
public FlagValue<int> Serve { get; set; }
}
[Fact]
public void Should_Throw_If_Command_Option_Value_Is_Optional_But_Type_Is_Not_A_Flag_Value()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
[CommandOption("--serve [PORT]")]
public FlagValue<int> Serve { get; set; }
}
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithOptionalOptionButNoFlagValue>>("foo");
});
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithNullableValueType : CommandSettings
// When
var result = Record.Exception(() => app.Run(new[] { "foo", "--serve", "123" }));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
[CommandOption("--serve [PORT]")]
public FlagValue<int?> Serve { get; set; }
}
ex.Message.ShouldBe("The option 'serve' has an optional value but does not implement IFlagValue.");
});
}
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithOptionalOptionButNoFlagValue : CommandSettings
[Fact]
public void Should_Set_Flag_And_Value_If_Both_Were_Provided()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
[CommandOption("--serve [PORT]")]
public int Serve { get; set; }
}
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
[SuppressMessage("Performance", "CA1812", Justification = "It's OK")]
private sealed class FlagSettingsWithDefaultValue : CommandSettings
// When
var result = app.Run(new[] { "foo", "--serve", "123", });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
[CommandOption("--serve [PORT]")]
[DefaultValue(987)]
public FlagValue<int> Serve { get; set; }
}
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(123);
});
}
[Fact]
public void Should_Throw_If_Command_Option_Value_Is_Optional_But_Type_Is_Not_A_Flag_Value()
[Fact]
public void Should_Only_Set_Flag_If_No_Value_Was_Provided()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithOptionalOptionButNoFlagValue>>("foo");
});
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
// When
var result = Record.Exception(() => app.Run(new[] { "foo", "--serve", "123" }));
// When
var result = app.Run(new[] { "foo", "--serve" });
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The option 'serve' has an optional value but does not implement IFlagValue.");
});
}
[Fact]
public void Should_Set_Flag_And_Value_If_Both_Were_Provided()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(0);
});
}
// When
var result = app.Run(new[] { "foo", "--serve", "123", });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(123);
});
}
[Fact]
public void Should_Only_Set_Flag_If_No_Value_Was_Provided()
[Fact]
public void Should_Set_Value_To_Default_Value_If_None_Was_Explicitly_Set()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithDefaultValue>>("foo");
});
// When
var result = app.Run(new[] { "foo", "--serve" });
// When
var result = app.Run(new[] { "foo", "--serve" });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(0);
});
}
[Fact]
public void Should_Set_Value_To_Default_Value_If_None_Was_Explicitly_Set()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettingsWithDefaultValue>().And(flag =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithDefaultValue>>("foo");
});
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(987);
});
}
// When
var result = app.Run(new[] { "foo", "--serve" });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettingsWithDefaultValue>().And(flag =>
{
flag.Serve.IsSet.ShouldBeTrue();
flag.Serve.Value.ShouldBe(987);
});
}
[Fact]
public void Should_Create_Unset_Instance_If_Flag_Was_Not_Set()
[Fact]
public void Should_Create_Unset_Instance_If_Flag_Was_Not_Set()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettings>>("foo");
});
// When
var result = app.Run(new[] { "foo" });
// When
var result = app.Run(new[] { "foo" });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
flag.Serve.IsSet.ShouldBeFalse();
flag.Serve.Value.ShouldBe(0);
});
}
[Fact]
public void Should_Create_Unset_Instance_With_Null_For_Nullable_Value_Type_If_Flag_Was_Not_Set()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettings>().And(flag =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithNullableValueType>>("foo");
});
flag.Serve.IsSet.ShouldBeFalse();
flag.Serve.Value.ShouldBe(0);
});
}
// When
var result = app.Run(new[] { "foo" });
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettingsWithNullableValueType>().And(flag =>
{
flag.Serve.IsSet.ShouldBeFalse();
flag.Serve.Value.ShouldBeNull();
});
}
[Theory]
[InlineData("Foo", true, "Set=True, Value=Foo")]
[InlineData("Bar", false, "Set=False, Value=Bar")]
public void Should_Return_Correct_String_Representation_From_ToString(
string value,
bool isSet,
string expected)
[Fact]
public void Should_Create_Unset_Instance_With_Null_For_Nullable_Value_Type_If_Flag_Was_Not_Set()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var flag = new FlagValue<string>
{
Value = value,
IsSet = isSet,
};
config.PropagateExceptions();
config.AddCommand<GenericCommand<FlagSettingsWithNullableValueType>>("foo");
});
// When
var result = flag.ToString();
// When
var result = app.Run(new[] { "foo" });
// Then
result.ShouldBe(expected);
}
[Theory]
[InlineData(true, "Set=True")]
[InlineData(false, "Set=False")]
public void Should_Return_Correct_String_Representation_From_ToString_If_Value_Is_Not_Set(
bool isSet,
string expected)
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<FlagSettingsWithNullableValueType>().And(flag =>
{
// Given
var flag = new FlagValue<string>
{
IsSet = isSet,
};
flag.Serve.IsSet.ShouldBeFalse();
flag.Serve.Value.ShouldBeNull();
});
}
// When
var result = flag.ToString();
[Theory]
[InlineData("Foo", true, "Set=True, Value=Foo")]
[InlineData("Bar", false, "Set=False, Value=Bar")]
public void Should_Return_Correct_String_Representation_From_ToString(
string value,
bool isSet,
string expected)
{
// Given
var flag = new FlagValue<string>
{
Value = value,
IsSet = isSet,
};
// Then
result.ShouldBe(expected);
}
// When
var result = flag.ToString();
// Then
result.ShouldBe(expected);
}
[Theory]
[InlineData(true, "Set=True")]
[InlineData(false, "Set=False")]
public void Should_Return_Correct_String_Representation_From_ToString_If_Value_Is_Not_Set(
bool isSet,
string expected)
{
// Given
var flag = new FlagValue<string>
{
IsSet = isSet,
};
// When
var result = flag.ToString();
// Then
result.ShouldBe(expected);
}
}
}
}

View File

@ -1,302 +1,293 @@
using System.Threading.Tasks;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Spectre.Verify.Extensions;
using VerifyXunit;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
[UsesVerify]
[ExpectationPath("Cli/Help")]
public class Help
{
[UsesVerify]
[ExpectationPath("Cli/Help")]
public class Help
[Fact]
[Expectation("Root")]
public Task Should_Output_Root_Correctly()
{
[Fact]
[Expectation("Root")]
public Task Should_Output_Root_Correctly()
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
configurator.AddCommand<GiraffeCommand>("giraffe");
});
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
configurator.AddCommand<GiraffeCommand>("giraffe");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Hidden_Commands")]
public Task Should_Skip_Hidden_Commands()
[Fact]
[Expectation("Hidden_Commands")]
public Task Should_Skip_Hidden_Commands()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
configurator.AddCommand<GiraffeCommand>("giraffe")
.WithExample(new[] { "giraffe", "123" })
.IsHidden();
});
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
configurator.AddCommand<GiraffeCommand>("giraffe")
.WithExample(new[] { "giraffe", "123" })
.IsHidden();
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Command")]
public Task Should_Output_Command_Correctly()
[Fact]
[Expectation("Command")]
public Task Should_Output_Command_Correctly()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
configurator.SetApplicationName("myapp");
configurator.AddBranch<CatSettings>("cat", animal =>
{
configurator.SetApplicationName("myapp");
configurator.AddBranch<CatSettings>("cat", animal =>
{
animal.SetDescription("Contains settings for a cat.");
animal.AddCommand<LionCommand>("lion");
});
animal.SetDescription("Contains settings for a cat.");
animal.AddCommand<LionCommand>("lion");
});
});
// When
var result = fixture.Run("cat", "--help");
// When
var result = fixture.Run("cat", "--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Leaf")]
public Task Should_Output_Leaf_Correctly()
[Fact]
[Expectation("Leaf")]
public Task Should_Output_Leaf_Correctly()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
configurator.SetApplicationName("myapp");
configurator.AddBranch<CatSettings>("cat", animal =>
{
configurator.SetApplicationName("myapp");
configurator.AddBranch<CatSettings>("cat", animal =>
{
animal.SetDescription("Contains settings for a cat.");
animal.AddCommand<LionCommand>("lion");
});
animal.SetDescription("Contains settings for a cat.");
animal.AddCommand<LionCommand>("lion");
});
});
// When
var result = fixture.Run("cat", "lion", "--help");
// When
var result = fixture.Run("cat", "lion", "--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Default")]
public Task Should_Output_Default_Command_Correctly()
[Fact]
[Expectation("Default")]
public Task Should_Output_Default_Command_Correctly()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<LionCommand>();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<LionCommand>();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
});
configurator.SetApplicationName("myapp");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("RootExamples")]
public Task Should_Output_Root_Examples_Defined_On_Root()
[Fact]
[Expectation("RootExamples")]
public Task Should_Output_Root_Examples_Defined_On_Root()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
configurator.AddExample(new[] { "horse", "--name", "Brutus" });
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
});
configurator.SetApplicationName("myapp");
configurator.AddExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
configurator.AddExample(new[] { "horse", "--name", "Brutus" });
configurator.AddCommand<DogCommand>("dog");
configurator.AddCommand<HorseCommand>("horse");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("RootExamples_Children")]
public Task Should_Output_Root_Examples_Defined_On_Direct_Children_If_Root_Have_No_Examples()
[Fact]
[Expectation("RootExamples_Children")]
public Task Should_Output_Root_Examples_Defined_On_Direct_Children_If_Root_Have_No_Examples()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog")
.WithExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
configurator.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "horse", "--name", "Brutus" });
});
configurator.SetApplicationName("myapp");
configurator.AddCommand<DogCommand>("dog")
.WithExample(new[] { "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
configurator.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "horse", "--name", "Brutus" });
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("RootExamples_Leafs")]
public Task Should_Output_Root_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
[Fact]
[Expectation("RootExamples_Leafs")]
public Task Should_Output_Root_Examples_Defined_On_Leaves_If_No_Other_Examples_Are_Found()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
configurator.SetApplicationName("myapp");
configurator.AddBranch<AnimalSettings>("animal", animal =>
{
configurator.SetApplicationName("myapp");
configurator.AddBranch<AnimalSettings>("animal", animal =>
{
animal.SetDescription("The animal command.");
animal.AddCommand<DogCommand>("dog")
.WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
animal.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "animal", "horse", "--name", "Brutus" });
});
animal.SetDescription("The animal command.");
animal.AddCommand<DogCommand>("dog")
.WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
animal.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "animal", "horse", "--name", "Brutus" });
});
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("CommandExamples")]
public Task Should_Only_Output_Command_Examples_Defined_On_Command()
[Fact]
[Expectation("CommandExamples")]
public Task Should_Only_Output_Command_Examples_Defined_On_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
configurator.SetApplicationName("myapp");
configurator.AddBranch<AnimalSettings>("animal", animal =>
{
configurator.SetApplicationName("myapp");
configurator.AddBranch<AnimalSettings>("animal", animal =>
{
animal.SetDescription("The animal command.");
animal.AddExample(new[] { "animal", "--help" });
animal.SetDescription("The animal command.");
animal.AddExample(new[] { "animal", "--help" });
animal.AddCommand<DogCommand>("dog")
.WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
animal.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "animal", "horse", "--name", "Brutus" });
});
animal.AddCommand<DogCommand>("dog")
.WithExample(new[] { "animal", "dog", "--name", "Rufus", "--age", "12", "--good-boy" });
animal.AddCommand<HorseCommand>("horse")
.WithExample(new[] { "animal", "horse", "--name", "Brutus" });
});
});
// When
var result = fixture.Run("animal", "--help");
// When
var result = fixture.Run("animal", "--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("DefaultExamples")]
public Task Should_Output_Root_Examples_If_Default_Command_Is_Specified()
[Fact]
[Expectation("DefaultExamples")]
public Task Should_Output_Root_Examples_If_Default_Command_Is_Specified()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<LionCommand>();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<LionCommand>();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddExample(new[] { "12", "-c", "3" });
});
configurator.SetApplicationName("myapp");
configurator.AddExample(new[] { "12", "-c", "3" });
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("NoDescription")]
public Task Should_Not_Show_Truncated_Command_Table_If_Commands_Are_Missing_Description()
[Fact]
[Expectation("NoDescription")]
public Task Should_Not_Show_Truncated_Command_Table_If_Commands_Are_Missing_Description()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
configurator.AddCommand<NoDescriptionCommand>("bar");
});
configurator.SetApplicationName("myapp");
configurator.AddCommand<NoDescriptionCommand>("bar");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("ArgumentOrder")]
public Task Should_List_Arguments_In_Correct_Order()
[Fact]
[Expectation("ArgumentOrder")]
public Task Should_List_Arguments_In_Correct_Order()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<GenericCommand<ArgumentOrderSettings>>();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<GenericCommand<ArgumentOrderSettings>>();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
});
configurator.SetApplicationName("myapp");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Show_Hidden_Command_Options()
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Show_Hidden_Command_Options()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<GenericCommand<HiddenOptionSettings>>();
fixture.Configure(configurator =>
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<GenericCommand<HiddenOptionSettings>>();
fixture.Configure(configurator =>
{
configurator.SetApplicationName("myapp");
});
configurator.SetApplicationName("myapp");
});
// When
var result = fixture.Run("--help");
// When
var result = fixture.Run("--help");
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
}
}
}

View File

@ -1,97 +1,90 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Injection
{
public sealed class Injection
public sealed class FakeDependency
{
public sealed class FakeDependency
}
public sealed class InjectSettings : CommandSettings
{
public FakeDependency Fake { get; set; }
[CommandOption("--name <NAME>")]
public string Name { get; }
[CommandOption("--age <AGE>")]
public int Age { get; set; }
public InjectSettings(FakeDependency fake, string name)
{
}
public sealed class InjectSettings : CommandSettings
{
public FakeDependency Fake { get; set; }
[CommandOption("--name <NAME>")]
public string Name { get; }
[CommandOption("--age <AGE>")]
public int Age { get; set; }
public InjectSettings(FakeDependency fake, string name)
{
Fake = fake;
Name = "Hello " + name;
}
}
[Fact]
public void Should_Inject_Parameters()
{
// Given
var app = new CommandAppTester();
var dependency = new FakeDependency();
app.SetDefaultCommand<GenericCommand<InjectSettings>>();
app.Configure(config =>
{
config.Settings.Registrar.RegisterInstance(dependency);
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--name", "foo",
"--age", "35",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
{
injected.ShouldNotBeNull();
injected.Fake.ShouldBeSameAs(dependency);
injected.Name.ShouldBe("Hello foo");
injected.Age.ShouldBe(35);
});
}
[Fact]
public void Should_Inject_Dependency_Using_A_Given_Registrar()
{
// Given
var dependency = new FakeDependency();
var registrar = new FakeTypeRegistrar { TypeResolverFactory = FakeTypeResolver.Factory };
registrar.RegisterInstance(typeof(FakeDependency), dependency);
var app = new CommandAppTester(registrar);
app.SetDefaultCommand<GenericCommand<InjectSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run(new[]
{
"--name", "foo",
"--age", "35",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
{
injected.ShouldNotBeNull();
injected.Fake.ShouldBeSameAs(dependency);
injected.Name.ShouldBe("Hello foo");
injected.Age.ShouldBe(35);
});
Fake = fake;
Name = "Hello " + name;
}
}
[Fact]
public void Should_Inject_Parameters()
{
// Given
var app = new CommandAppTester();
var dependency = new FakeDependency();
app.SetDefaultCommand<GenericCommand<InjectSettings>>();
app.Configure(config =>
{
config.Settings.Registrar.RegisterInstance(dependency);
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--name", "foo",
"--age", "35",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
{
injected.ShouldNotBeNull();
injected.Fake.ShouldBeSameAs(dependency);
injected.Name.ShouldBe("Hello foo");
injected.Age.ShouldBe(35);
});
}
[Fact]
public void Should_Inject_Dependency_Using_A_Given_Registrar()
{
// Given
var dependency = new FakeDependency();
var registrar = new FakeTypeRegistrar { TypeResolverFactory = FakeTypeResolver.Factory };
registrar.RegisterInstance(typeof(FakeDependency), dependency);
var app = new CommandAppTester(registrar);
app.SetDefaultCommand<GenericCommand<InjectSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run(new[]
{
"--name", "foo",
"--age", "35",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<InjectSettings>().And(injected =>
{
injected.ShouldNotBeNull();
injected.Fake.ShouldBeSameAs(dependency);
injected.Name.ShouldBe("Hello foo");
injected.Age.ShouldBe(35);
});
}
}
}
}

View File

@ -1,327 +1,316 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Pairs
{
public sealed class Pairs
public sealed class AmbiguousSettings : CommandSettings
{
public sealed class AmbiguousSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
[TypeConverter(typeof(CatAgilityConverter))]
public ILookup<string, string> Values { get; set; }
}
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
[TypeConverter(typeof(CatAgilityConverter))]
public ILookup<string, string> Values { get; set; }
}
public sealed class NotDeconstructableSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public string Values { get; set; }
}
public sealed class NotDeconstructableSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public string Values { get; set; }
}
public sealed class DefaultPairDeconstructorSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
public IDictionary<string, int> Values { get; set; }
}
public sealed class DefaultPairDeconstructorSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
public IDictionary<string, int> Values { get; set; }
}
public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
public IDictionary<string, DayOfWeek> Values { get; set; }
}
public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
public IDictionary<string, DayOfWeek> Values { get; set; }
}
public sealed class LookupSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public ILookup<string, string> Values { get; set; }
}
public sealed class LookupSettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public ILookup<string, string> Values { get; set; }
}
public sealed class DictionarySettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public IDictionary<string, string> Values { get; set; }
}
public sealed class DictionarySettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public IDictionary<string, string> Values { get; set; }
}
public sealed class ReadOnlyDictionarySettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public IReadOnlyDictionary<string, string> Values { get; set; }
}
public sealed class ReadOnlyDictionarySettings : CommandSettings
{
[CommandOption("--var <VALUE>")]
[PairDeconstructor(typeof(StringIntDeconstructor))]
public IReadOnlyDictionary<string, string> Values { get; set; }
}
public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
{
protected override (string Key, string Value) Deconstruct(string value)
{
protected override (string Key, string Value) Deconstruct(string value)
if (value == null)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
var parts = value.Split(new[] { '=' });
if (parts.Length != 2)
{
throw new InvalidOperationException("Could not parse pair");
}
return (parts[0], parts[1]);
throw new ArgumentNullException(nameof(value));
}
}
[Fact]
public void Should_Throw_If_Option_Has_Pair_Deconstructor_And_Type_Converter()
{
// Given
var app = new CommandApp<GenericCommand<AmbiguousSettings>>();
app.Configure(config =>
var parts = value.Split(new[] { '=' });
if (parts.Length != 2)
{
config.PropagateExceptions();
});
throw new InvalidOperationException("Could not parse pair");
}
// When
var result = Record.Exception(() => app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The option 'var' is both marked as pair deconstructable and convertable.");
});
}
[Fact]
public void Should_Throw_If_Option_Has_Pair_Deconstructor_But_Type_Is_Not_Deconstructable()
{
// Given
var app = new CommandApp<GenericCommand<NotDeconstructableSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The option 'var' is marked as pair deconstructable, but the underlying type does not support that.");
});
}
[Fact]
public void Should_Map_Pairs_To_Pair_Deconstructable_Collection_Using_Default_Deconstructort()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=1",
"--var", "foo=3",
"--var", "bar=4",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DefaultPairDeconstructorSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe(3);
pair.Values["bar"].ShouldBe(4);
});
}
[Fact]
public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=Monday",
"--var", "bar=Tuesday",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
});
}
[Theory]
[InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
[InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
public void Should_Throw_If_Value_Is_Not_In_A_Valid_Format_Using_Default_Deconstructor(
string input, string expected)
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
// When
var result = app.Run(new[]
{
"--var", input,
});
// Then
result.ExitCode.ShouldBe(-1);
result.Output.ShouldBe(expected);
}
[Fact]
public void Should_Map_Lookup_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<LookupSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<LookupSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(1);
pair.Values["foo"].ToList().Count.ShouldBe(2);
});
}
[Fact]
public void Should_Map_Dictionary_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "baz=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe("bar");
pair.Values["baz"].ShouldBe("qux");
});
}
[Fact]
public void Should_Map_Latest_Value_Of_Same_Key_When_Mapping_To_Dictionary()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(1);
pair.Values["foo"].ShouldBe("qux");
});
}
[Fact]
public void Should_Map_ReadOnly_Dictionary_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ReadOnlyDictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "baz=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ReadOnlyDictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe("bar");
pair.Values["baz"].ShouldBe("qux");
});
return (parts[0], parts[1]);
}
}
[Fact]
public void Should_Throw_If_Option_Has_Pair_Deconstructor_And_Type_Converter()
{
// Given
var app = new CommandApp<GenericCommand<AmbiguousSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The option 'var' is both marked as pair deconstructable and convertable.");
});
}
[Fact]
public void Should_Throw_If_Option_Has_Pair_Deconstructor_But_Type_Is_Not_Deconstructable()
{
// Given
var app = new CommandApp<GenericCommand<NotDeconstructableSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The option 'var' is marked as pair deconstructable, but the underlying type does not support that.");
});
}
[Fact]
public void Should_Map_Pairs_To_Pair_Deconstructable_Collection_Using_Default_Deconstructort()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=1",
"--var", "foo=3",
"--var", "bar=4",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DefaultPairDeconstructorSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe(3);
pair.Values["bar"].ShouldBe(4);
});
}
[Fact]
public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=Monday",
"--var", "bar=Tuesday",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
});
}
[Theory]
[InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
[InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
public void Should_Throw_If_Value_Is_Not_In_A_Valid_Format_Using_Default_Deconstructor(
string input, string expected)
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
// When
var result = app.Run(new[]
{
"--var", input,
});
// Then
result.ExitCode.ShouldBe(-1);
result.Output.ShouldBe(expected);
}
[Fact]
public void Should_Map_Lookup_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<LookupSettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<LookupSettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(1);
pair.Values["foo"].ToList().Count.ShouldBe(2);
});
}
[Fact]
public void Should_Map_Dictionary_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "baz=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe("bar");
pair.Values["baz"].ShouldBe("qux");
});
}
[Fact]
public void Should_Map_Latest_Value_Of_Same_Key_When_Mapping_To_Dictionary()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "foo=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(1);
pair.Values["foo"].ShouldBe("qux");
});
}
[Fact]
public void Should_Map_ReadOnly_Dictionary_Values()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ReadOnlyDictionarySettings>>();
app.Configure(config =>
{
config.PropagateExceptions();
});
// When
var result = app.Run(new[]
{
"--var", "foo=bar",
"--var", "baz=qux",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ReadOnlyDictionarySettings>().And(pair =>
{
pair.Values.ShouldNotBeNull();
pair.Values.Count.ShouldBe(2);
pair.Values["foo"].ShouldBe("bar");
pair.Values["baz"].ShouldBe("qux");
});
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +1,70 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Remaining
{
public sealed class Remaining
[Fact]
public void Should_Register_Remaining_Parsed_Arguments_With_Context()
{
[Fact]
public void Should_Register_Remaining_Parsed_Arguments_With_Context()
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
});
animal.AddCommand<DogCommand>("dog");
});
});
// When
var result = app.Run(new[]
{
"animal", "4", "dog", "12", "--",
"--foo", "bar", "--foo", "baz",
"-bar", "\"baz\"", "qux",
"foo bar baz qux",
});
// Then
result.Context.Remaining.Parsed.Count.ShouldBe(4);
result.Context.ShouldHaveRemainingArgument("foo", values: new[] { "bar", "baz" });
result.Context.ShouldHaveRemainingArgument("b", values: new[] { (string)null });
result.Context.ShouldHaveRemainingArgument("a", values: new[] { (string)null });
result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
}
[Fact]
public void Should_Register_Remaining_Raw_Arguments_With_Context()
// When
var result = app.Run(new[]
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
});
});
"animal", "4", "dog", "12", "--",
"--foo", "bar", "--foo", "baz",
"-bar", "\"baz\"", "qux",
"foo bar baz qux",
});
// When
var result = app.Run(new[]
{
"animal", "4", "dog", "12", "--",
"--foo", "bar", "-bar", "\"baz\"", "qux",
"foo bar baz qux",
});
// Then
result.Context.Remaining.Parsed.Count.ShouldBe(4);
result.Context.ShouldHaveRemainingArgument("foo", values: new[] { "bar", "baz" });
result.Context.ShouldHaveRemainingArgument("b", values: new[] { (string)null });
result.Context.ShouldHaveRemainingArgument("a", values: new[] { (string)null });
result.Context.ShouldHaveRemainingArgument("r", values: new[] { (string)null });
}
// Then
result.Context.Remaining.Raw.Count.ShouldBe(6);
result.Context.Remaining.Raw[0].ShouldBe("--foo");
result.Context.Remaining.Raw[1].ShouldBe("bar");
result.Context.Remaining.Raw[2].ShouldBe("-bar");
result.Context.Remaining.Raw[3].ShouldBe("baz");
result.Context.Remaining.Raw[4].ShouldBe("qux");
result.Context.Remaining.Raw[5].ShouldBe("foo bar baz qux");
}
[Fact]
public void Should_Register_Remaining_Raw_Arguments_With_Context()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
});
});
// When
var result = app.Run(new[]
{
"animal", "4", "dog", "12", "--",
"--foo", "bar", "-bar", "\"baz\"", "qux",
"foo bar baz qux",
});
// Then
result.Context.Remaining.Raw.Count.ShouldBe(6);
result.Context.Remaining.Raw[0].ShouldBe("--foo");
result.Context.Remaining.Raw[1].ShouldBe("bar");
result.Context.Remaining.Raw[2].ShouldBe("-bar");
result.Context.Remaining.Raw[3].ShouldBe("baz");
result.Context.Remaining.Raw[4].ShouldBe("qux");
result.Context.Remaining.Raw[5].ShouldBe("foo bar baz qux");
}
}
}
}

View File

@ -1,118 +1,111 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandApptests
{
public sealed partial class CommandApptests
[Fact]
public void Should_Treat_Commands_As_Case_Sensitive_If_Specified()
{
[Fact]
public void Should_Treat_Commands_As_Case_Sensitive_If_Specified()
// Given
var app = new CommandApp();
app.Configure(config =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.Commands);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.Commands);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"Command", "--foo", "bar",
}));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
ex.Message.ShouldBe("Unknown command 'Command'.");
});
}
[Fact]
public void Should_Treat_Long_Options_As_Case_Sensitive_If_Specified()
// When
var result = Record.Exception(() => app.Run(new[]
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.LongOptions);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
"Command", "--foo", "bar",
}));
// When
var result = Record.Exception(() => app.Run(new[]
{
"command", "--Foo", "bar",
}));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
ex.Message.ShouldBe("Unknown option 'Foo'.");
});
}
[Fact]
public void Should_Treat_Short_Options_As_Case_Sensitive()
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"command", "-F", "bar",
}));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
ex.Message.ShouldBe("Unknown option 'F'.");
});
}
[Fact]
public void Should_Suppress_Case_Sensitivity_If_Specified()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.None);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = app.Run(new[]
{
"Command", "--Foo", "bar",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<StringOptionSettings>().And(vec =>
{
vec.Foo.ShouldBe("bar");
});
}
ex.Message.ShouldBe("Unknown command 'Command'.");
});
}
}
[Fact]
public void Should_Treat_Long_Options_As_Case_Sensitive_If_Specified()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.LongOptions);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"command", "--Foo", "bar",
}));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
ex.Message.ShouldBe("Unknown option 'Foo'.");
});
}
[Fact]
public void Should_Treat_Short_Options_As_Case_Sensitive()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = Record.Exception(() => app.Run(new[]
{
"command", "-F", "bar",
}));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<CommandParseException>().And(ex =>
{
ex.Message.ShouldBe("Unknown option 'F'.");
});
}
[Fact]
public void Should_Suppress_Case_Sensitivity_If_Specified()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.UseStrictParsing();
config.PropagateExceptions();
config.CaseSensitivity(CaseSensitivity.None);
config.AddCommand<GenericCommand<StringOptionSettings>>("command");
});
// When
var result = app.Run(new[]
{
"Command", "--Foo", "bar",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<StringOptionSettings>().And(vec =>
{
vec.Foo.ShouldBe("bar");
});
}
}

View File

@ -1,26 +1,21 @@
using Shouldly;
using Spectre.Console.Cli;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
[Fact]
public void Should_Apply_Case_Sensitivity_For_Everything_By_Default()
{
[Fact]
public void Should_Apply_Case_Sensitivity_For_Everything_By_Default()
// Given
var app = new CommandApp();
// When
var defaultSensitivity = CaseSensitivity.None;
app.Configure(config =>
{
// Given
var app = new CommandApp();
defaultSensitivity = config.Settings.CaseSensitivity;
});
// When
var defaultSensitivity = CaseSensitivity.None;
app.Configure(config =>
{
defaultSensitivity = config.Settings.CaseSensitivity;
});
// Then
defaultSensitivity.ShouldBe(CaseSensitivity.All);
}
// Then
defaultSensitivity.ShouldBe(CaseSensitivity.All);
}
}
}

View File

@ -1,40 +1,33 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class TypeConverters
{
public sealed class TypeConverters
[Fact]
public void Should_Bind_Using_Custom_Type_Converter_If_Specified()
{
[Fact]
public void Should_Bind_Using_Custom_Type_Converter_If_Specified()
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<CatCommand>("cat");
});
config.PropagateExceptions();
config.AddCommand<CatCommand>("cat");
});
// When
var result = app.Run(new[]
{
"cat", "--name", "Tiger",
"--agility", "FOOBAR",
});
// When
var result = app.Run(new[]
{
"cat", "--name", "Tiger",
"--agility", "FOOBAR",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
{
cat.Agility.ShouldBe(6);
});
}
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<CatSettings>().And(cat =>
{
cat.Agility.ShouldBe(6);
});
}
}
}
}

View File

@ -1,299 +1,291 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Cli.Unsafe;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class SafetyOff
{
public sealed class SafetyOff
[Fact]
public void Can_Mix_Safe_And_Unsafe_Configurators()
{
[Fact]
public void Can_Mix_Safe_And_Unsafe_Configurators()
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.SafetyOff().AddBranch("mammal", typeof(MammalSettings), mammal =>
{
animal.SafetyOff().AddBranch("mammal", typeof(MammalSettings), mammal =>
{
mammal.AddCommand("dog", typeof(DogCommand));
mammal.AddCommand("horse", typeof(HorseCommand));
});
mammal.AddCommand("dog", typeof(DogCommand));
mammal.AddCommand("horse", typeof(HorseCommand));
});
});
});
// When
var result = app.Run(new[]
{
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
[Fact]
public void Can_Turn_Safety_On_After_Turning_It_Off_For_Branch()
// When
var result = app.Run(new[]
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
[Fact]
public void Can_Turn_Safety_On_After_Turning_It_Off_For_Branch()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.SafetyOn<AnimalSettings>()
.AddBranch<MammalSettings>("mammal", mammal =>
{
animal.SafetyOn<AnimalSettings>()
.AddBranch<MammalSettings>("mammal", mammal =>
{
mammal.SafetyOff().AddCommand("dog", typeof(DogCommand));
mammal.AddCommand<HorseCommand>("horse");
});
mammal.SafetyOff().AddCommand("dog", typeof(DogCommand));
mammal.AddCommand<HorseCommand>("horse");
});
});
});
// When
var result = app.Run(new[]
{
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
[Fact]
public void Should_Throw_If_Trying_To_Convert_Unsafe_Branch_Configurator_To_Safe_Version_With_Wrong_Type()
// When
var result = app.Run(new[]
{
// Given
var app = new CommandApp();
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
// When
var result = Record.Exception(() => app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.SafetyOn<MammalSettings>().AddCommand<DogCommand>("dog");
});
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>();
result.Message.ShouldBe("Configurator cannot be converted to a safe configurator of type 'MammalSettings'.");
}
[Fact]
public void Should_Pass_Case_1()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
[Fact]
public void Should_Throw_If_Trying_To_Convert_Unsafe_Branch_Configurator_To_Safe_Version_With_Wrong_Type()
{
// Given
var app = new CommandApp();
// When
var result = Record.Exception(() => app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.SafetyOn<MammalSettings>().AddCommand<DogCommand>("dog");
});
}));
// Then
result.ShouldBeOfType<CommandConfigurationException>();
result.Message.ShouldBe("Configurator cannot be converted to a safe configurator of type 'MammalSettings'.");
}
[Fact]
public void Should_Pass_Case_1()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.AddBranch("mammal", typeof(MammalSettings), mammal =>
{
animal.AddBranch("mammal", typeof(MammalSettings), mammal =>
{
mammal.AddCommand("dog", typeof(DogCommand));
mammal.AddCommand("horse", typeof(HorseCommand));
});
mammal.AddCommand("dog", typeof(DogCommand));
mammal.AddCommand("horse", typeof(HorseCommand));
});
});
});
// When
var result = app.Run(new[]
{
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
[Fact]
public void Should_Pass_Case_2()
// When
var result = app.Run(new[]
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddCommand("dog", typeof(DogCommand));
});
"animal", "--alive", "mammal", "--name",
"Rufus", "dog", "12", "--good-boy",
});
// When
var result = app.Run(new[]
{
"dog", "12", "4", "--good-boy",
"--name", "Rufus", "--alive",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Legs.ShouldBe(12);
dog.Age.ShouldBe(4);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
[Fact]
public void Should_Pass_Case_3()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.AddCommand("dog", typeof(DogCommand));
animal.AddCommand("horse", typeof(HorseCommand));
});
});
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
// When
var result = app.Run(new[]
{
"animal", "dog", "12", "--good-boy",
"--name", "Rufus",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(false);
});
}
[Fact]
public void Should_Pass_Case_4()
[Fact]
public void Should_Pass_Case_2()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
animal.AddCommand("dog", typeof(DogCommand));
});
});
config.PropagateExceptions();
config.SafetyOff().AddCommand("dog", typeof(DogCommand));
});
// When
var result = app.Run(new[]
{
"animal", "4", "dog", "12",
"--good-boy", "--name", "Rufus",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Legs.ShouldBe(4);
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.IsAlive.ShouldBe(false);
dog.Name.ShouldBe("Rufus");
});
}
[Fact]
public void Should_Pass_Case_5()
// When
var result = app.Run(new[]
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddCommand("multi", typeof(OptionVectorCommand));
});
"dog", "12", "4", "--good-boy",
"--name", "Rufus", "--alive",
});
// When
var result = app.Run(new[]
{
"multi", "--foo", "a", "--foo", "b", "--bar", "1", "--foo", "c", "--bar", "2",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo.ShouldBe(new[] { "a", "b", "c" });
vec.Bar.Length.ShouldBe(2);
vec.Bar.ShouldBe(new[] { 1, 2 });
});
}
[Fact]
public void Should_Pass_Case_6()
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
});
dog.Legs.ShouldBe(12);
dog.Age.ShouldBe(4);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(true);
});
}
// When
var result = app.Run(new[]
[Fact]
public void Should_Pass_Case_3()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
"multi", "a", "b", "c",
animal.AddCommand("dog", typeof(DogCommand));
animal.AddCommand("horse", typeof(HorseCommand));
});
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
// When
var result = app.Run(new[]
{
"animal", "dog", "12", "--good-boy",
"--name", "Rufus",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.Name.ShouldBe("Rufus");
dog.IsAlive.ShouldBe(false);
});
}
[Fact]
public void Should_Pass_Case_4()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo.ShouldBe(new[] { "a", "b", "c" });
animal.AddCommand("dog", typeof(DogCommand));
});
}
});
// When
var result = app.Run(new[]
{
"animal", "4", "dog", "12",
"--good-boy", "--name", "Rufus",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{
dog.Legs.ShouldBe(4);
dog.Age.ShouldBe(12);
dog.GoodBoy.ShouldBe(true);
dog.IsAlive.ShouldBe(false);
dog.Name.ShouldBe("Rufus");
});
}
[Fact]
public void Should_Pass_Case_5()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.SafetyOff().AddCommand("multi", typeof(OptionVectorCommand));
});
// When
var result = app.Run(new[]
{
"multi", "--foo", "a", "--foo", "b", "--bar", "1", "--foo", "c", "--bar", "2",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo.ShouldBe(new[] { "a", "b", "c" });
vec.Bar.Length.ShouldBe(2);
vec.Bar.ShouldBe(new[] { 1, 2 });
});
}
[Fact]
public void Should_Pass_Case_6()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
});
// When
var result = app.Run(new[]
{
"multi", "a", "b", "c",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo.ShouldBe(new[] { "a", "b", "c" });
});
}
}
}
}

View File

@ -1,88 +1,82 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Validation
{
public sealed class Validation
[Fact]
public void Should_Throw_If_Attribute_Validation_Fails()
{
[Fact]
public void Should_Throw_If_Attribute_Validation_Fails()
// Given
var app = new CommandApp();
app.Configure(config =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
});
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "3", "dog", "7", "--name", "Rufus" }));
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "3", "dog", "7", "--name", "Rufus" }));
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
{
e.Message.ShouldBe("Animals must have an even number of legs.");
});
}
[Fact]
public void Should_Throw_If_Settings_Validation_Fails()
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
});
e.Message.ShouldBe("Animals must have an even number of legs.");
});
}
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "7", "--name", "Tiger" }));
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
{
e.Message.ShouldBe("Tiger is not a dog name!");
});
}
[Fact]
public void Should_Throw_If_Command_Validation_Fails()
[Fact]
public void Should_Throw_If_Settings_Validation_Fails()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
});
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" }));
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "7", "--name", "Tiger" }));
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
{
e.Message.ShouldBe("Tiger is not a dog name!");
});
}
[Fact]
public void Should_Throw_If_Command_Validation_Fails()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
e.Message.ShouldBe("Dog is too old...");
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
}
});
// When
var result = Record.Exception(() => app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" }));
// Then
result.ShouldBeOfType<CommandRuntimeException>().And(e =>
{
e.Message.ShouldBe("Dog is too old...");
});
}
}
}
}

View File

@ -1,97 +1,88 @@
using System.ComponentModel;
using System.Globalization;
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class ValueProviders
{
public sealed class ValueProviders
public sealed class ValueProviderSettings : CommandSettings
{
public sealed class ValueProviderSettings : CommandSettings
[CommandOption("-f|--foo <VALUE>")]
[IntegerValueProvider(32)]
[TypeConverter(typeof(HexConverter))]
public string Foo { get; set; }
}
public sealed class IntegerValueProvider : ParameterValueProviderAttribute
{
private readonly int _value;
public IntegerValueProvider(int value)
{
[CommandOption("-f|--foo <VALUE>")]
[IntegerValueProvider(32)]
[TypeConverter(typeof(HexConverter))]
public string Foo { get; set; }
_value = value;
}
public sealed class IntegerValueProvider : ParameterValueProviderAttribute
public override bool TryGetValue(CommandParameterContext context, out object result)
{
private readonly int _value;
public IntegerValueProvider(int value)
if (context.Value == null)
{
_value = value;
result = _value;
return true;
}
public override bool TryGetValue(CommandParameterContext context, out object result)
{
if (context.Value == null)
{
result = _value;
return true;
}
result = null;
return false;
}
}
public sealed class HexConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is int integer)
{
return integer.ToString("X");
}
return value is string stringValue && int.TryParse(stringValue, out var intValue)
? intValue.ToString("X")
: base.ConvertFrom(context, culture, value);
}
}
[Fact]
public void Should_Use_Provided_Value_If_No_Value_Was_Specified()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run();
// Then
result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
{
settings.Foo.ShouldBe("20"); // 32 is 0x20
});
}
[Fact]
public void Should_Not_Override_Value_If_Value_Was_Specified()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run("--foo", "12");
// Then
result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
{
settings.Foo.ShouldBe("C"); // 12 is 0xC
});
result = null;
return false;
}
}
public sealed class HexConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is int integer)
{
return integer.ToString("X");
}
return value is string stringValue && int.TryParse(stringValue, out var intValue)
? intValue.ToString("X")
: base.ConvertFrom(context, culture, value);
}
}
[Fact]
public void Should_Use_Provided_Value_If_No_Value_Was_Specified()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run();
// Then
result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
{
settings.Foo.ShouldBe("20"); // 32 is 0x20
});
}
[Fact]
public void Should_Not_Override_Value_If_Value_Was_Specified()
{
// Given
var app = new CommandAppTester();
app.SetDefaultCommand<GenericCommand<ValueProviderSettings>>();
app.Configure(config => config.PropagateExceptions());
// When
var result = app.Run("--foo", "12");
// Then
result.Settings.ShouldBeOfType<ValueProviderSettings>().And(settings =>
{
settings.Foo.ShouldBe("C"); // 12 is 0xC
});
}
}
}
}

View File

@ -1,111 +1,104 @@
using Shouldly;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Vectors
{
public sealed class Vectors
[Fact]
public void Should_Throw_If_A_Single_Command_Has_Multiple_Argument_Vectors()
{
[Fact]
public void Should_Throw_If_A_Single_Command_Has_Multiple_Argument_Vectors()
// Given
var app = new CommandApp();
app.Configure(config =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<MultipleArgumentVectorSettings>>("multi");
});
config.PropagateExceptions();
config.AddCommand<GenericCommand<MultipleArgumentVectorSettings>>("multi");
});
// When
var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
// When
var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The command 'multi' specifies more than one vector argument.");
});
}
[Fact]
public void Should_Throw_If_An_Argument_Vector_Is_Not_Specified_Last()
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<MultipleArgumentVectorSpecifiedFirstSettings>>("multi");
});
ex.Message.ShouldBe("The command 'multi' specifies more than one vector argument.");
});
}
// When
var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The command 'multi' specifies an argument vector that is not the last argument.");
});
}
[Fact]
public void Should_Assign_Values_To_Argument_Vector()
[Fact]
public void Should_Throw_If_An_Argument_Vector_Is_Not_Specified_Last()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
});
config.PropagateExceptions();
config.AddCommand<GenericCommand<MultipleArgumentVectorSpecifiedFirstSettings>>("multi");
});
// When
var result = app.Run(new[]
{
"multi", "a", "b", "c",
});
// When
var result = Record.Exception(() => app.Run(new[] { "multi", "a", "b", "c" }));
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo[0].ShouldBe("a");
vec.Foo[1].ShouldBe("b");
vec.Foo[2].ShouldBe("c");
});
}
[Fact]
public void Should_Assign_Values_To_Option_Vector()
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<OptionVectorCommand>("cmd");
});
ex.Message.ShouldBe("The command 'multi' specifies an argument vector that is not the last argument.");
});
}
// When
var result = app.Run(new[]
{
"cmd", "--foo", "red",
"--bar", "4", "--foo", "blue",
});
[Fact]
public void Should_Assign_Values_To_Argument_Vector()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<GenericCommand<ArgumentVectorSettings>>("multi");
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
{
vec.Foo.ShouldBe(new string[] { "red", "blue" });
vec.Bar.ShouldBe(new int[] { 4 });
});
}
// When
var result = app.Run(new[]
{
"multi", "a", "b", "c",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<ArgumentVectorSettings>().And(vec =>
{
vec.Foo.Length.ShouldBe(3);
vec.Foo[0].ShouldBe("a");
vec.Foo[1].ShouldBe("b");
vec.Foo[2].ShouldBe("c");
});
}
[Fact]
public void Should_Assign_Values_To_Option_Vector()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<OptionVectorCommand>("cmd");
});
// When
var result = app.Run(new[]
{
"cmd", "--foo", "red",
"--bar", "4", "--foo", "blue",
});
// Then
result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
{
vec.Foo.ShouldBe(new string[] { "red", "blue" });
vec.Bar.ShouldBe(new int[] { 4 });
});
}
}
}
}

View File

@ -1,37 +1,31 @@
using Shouldly;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
public sealed class Version
{
public sealed class Version
[Fact]
public void Should_Output_The_Version_To_The_Console()
{
[Fact]
public void Should_Output_The_Version_To_The_Console()
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.AddBranch<AnimalSettings>("animal", animal =>
animal.AddBranch<MammalSettings>("mammal", mammal =>
{
animal.AddBranch<MammalSettings>("mammal", mammal =>
{
mammal.AddCommand<DogCommand>("dog");
mammal.AddCommand<HorseCommand>("horse");
});
mammal.AddCommand<DogCommand>("dog");
mammal.AddCommand<HorseCommand>("horse");
});
});
});
// When
var result = fixture.Run(Constants.VersionCommand);
// When
var result = fixture.Run(Constants.VersionCommand);
// Then
result.Output.ShouldStartWith("Spectre.Cli version ");
}
// Then
result.Output.ShouldStartWith("Spectre.Cli version ");
}
}
}
}

View File

@ -1,157 +1,148 @@
using System.Threading.Tasks;
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Spectre.Console.Tests.Data;
using Spectre.Verify.Extensions;
using VerifyXunit;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed partial class CommandAppTests
{
public sealed partial class CommandAppTests
[UsesVerify]
[ExpectationPath("Cli/Xml")]
public sealed class Xml
{
[UsesVerify]
[ExpectationPath("Cli/Xml")]
public sealed class Xml
[Fact]
[Expectation("Test_1")]
public Task Should_Dump_Correct_Model_For_Case_1()
{
[Fact]
[Expectation("Test_1")]
public Task Should_Dump_Correct_Model_For_Case_1()
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
animal.AddBranch<MammalSettings>("mammal", mammal =>
{
animal.AddBranch<MammalSettings>("mammal", mammal =>
{
mammal.AddCommand<DogCommand>("dog");
mammal.AddCommand<HorseCommand>("horse");
});
mammal.AddCommand<DogCommand>("dog");
mammal.AddCommand<HorseCommand>("horse");
});
});
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_2")]
public Task Should_Dump_Correct_Model_For_Case_2()
[Fact]
[Expectation("Test_2")]
public Task Should_Dump_Correct_Model_For_Case_2()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
config.AddCommand<DogCommand>("dog");
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_3")]
public Task Should_Dump_Correct_Model_For_Case_3()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.AddCommand<DogCommand>("dog");
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_3")]
public Task Should_Dump_Correct_Model_For_Case_3()
[Fact]
[Expectation("Test_4")]
public Task Should_Dump_Correct_Model_For_Case_4()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
config.AddBranch<AnimalSettings>("animal", animal =>
{
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
});
animal.AddCommand<DogCommand>("dog");
});
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_4")]
public Task Should_Dump_Correct_Model_For_Case_4()
[Fact]
[Expectation("Test_5")]
public Task Should_Dump_Correct_Model_For_Case_5()
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
});
});
config.AddCommand<OptionVectorCommand>("cmd");
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_5")]
public Task Should_Dump_Correct_Model_For_Case_5()
[Fact]
[Expectation("Test_6")]
public Task Should_Dump_Correct_Model_For_Model_With_Default_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<DogCommand>();
fixture.Configure(config =>
{
// Given
var fixture = new CommandAppTester();
fixture.Configure(config =>
{
config.AddCommand<OptionVectorCommand>("cmd");
});
config.AddCommand<HorseCommand>("horse");
});
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Test_6")]
public Task Should_Dump_Correct_Model_For_Model_With_Default_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<DogCommand>();
fixture.Configure(config =>
{
config.AddCommand<HorseCommand>("horse");
});
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Dump_Hidden_Options_On_A_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<HiddenOptionsCommand>();
// When
var result = fixture.Run(Constants.XmlDocCommand);
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
[Fact]
[Expectation("Hidden_Command_Options")]
public Task Should_Not_Dump_Hidden_Options_On_A_Command()
{
// Given
var fixture = new CommandAppTester();
fixture.SetDefaultCommand<HiddenOptionsCommand>();
// When
var result = fixture.Run(Constants.XmlDocCommand);
// Then
return Verifier.Verify(result.Output);
}
// Then
return Verifier.Verify(result.Output);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,11 @@
using Spectre.Console.Cli;
using Spectre.Console.Testing;
using Xunit;
namespace Spectre.Console.Tests.Unit.Cli;
namespace Spectre.Console.Tests.Unit.Cli
public sealed class DefaultTypeRegistrarTests
{
public sealed class DefaultTypeRegistrarTests
[Fact]
public void Should_Pass_Base_Registrar_Tests()
{
[Fact]
public void Should_Pass_Base_Registrar_Tests()
{
var harness = new TypeRegistrarBaseTests(() => new DefaultTypeRegistrar());
harness.RunAllTests();
}
var harness = new TypeRegistrarBaseTests(() => new DefaultTypeRegistrar());
harness.RunAllTests();
}
}
}