mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Moved analyzer tests to its own project
Also moves tests to `./test` which makes it possible for all test projects to share the same .editorconfig files and similar.
This commit is contained in:
@ -0,0 +1,97 @@
|
||||
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
|
||||
{
|
||||
[ExpectationPath("Cli/Arguments")]
|
||||
public sealed partial class CommandArgumentAttributeTests
|
||||
{
|
||||
[UsesVerify]
|
||||
public sealed class ArgumentCannotContainOptions
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class MultipleValuesAreNotSupported
|
||||
{
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<FOO> <BAR>")]
|
||||
public string Foo { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("MultipleValuesAreNotSupported")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given, When
|
||||
var result = Fixture.Run<Settings>();
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class ValuesMustHaveName
|
||||
{
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<>")]
|
||||
public string Foo { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("ValuesMustHaveName")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given, When
|
||||
var result = Fixture.Run<Settings>();
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
|
||||
{
|
||||
public sealed partial class CommandArgumentAttributeTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Not_Contain_Options()
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
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
|
||||
{
|
||||
[ExpectationPath("Cli/Arguments")]
|
||||
public sealed partial class CommandOptionAttributeTests
|
||||
{
|
||||
[UsesVerify]
|
||||
public sealed class UnexpectedCharacter
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli.Annotations
|
||||
{
|
||||
public sealed partial class CommandOptionAttributeTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Parse_Short_Name_Correctly()
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public class NullableSettings : CommandSettings
|
||||
{
|
||||
public NullableSettings(bool? detailed, string[] extra)
|
||||
{
|
||||
Detailed = detailed;
|
||||
Extra = extra;
|
||||
}
|
||||
|
||||
[CommandOption("-d")]
|
||||
public bool? Detailed { get; }
|
||||
|
||||
[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" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class FlagValues
|
||||
{
|
||||
[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 =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettingsWithOptionalOptionButNoFlagValue>>("foo");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(new[] { "foo", "--serve", "123" }));
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettings>>("foo");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettings>>("foo");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettingsWithDefaultValue>>("foo");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettings>>("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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FlagSettingsWithNullableValueType>>("foo");
|
||||
});
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Given
|
||||
var flag = new FlagValue<string>
|
||||
{
|
||||
Value = value,
|
||||
IsSet = isSet,
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
283
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Help.cs
Normal file
283
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Help.cs
Normal file
@ -0,0 +1,283 @@
|
||||
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
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
[UsesVerify]
|
||||
[ExpectationPath("Cli/Help")]
|
||||
public class Help
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Root")]
|
||||
public Task Should_Output_Root_Correctly()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
configurator.AddCommand<HorseCommand>("horse");
|
||||
configurator.AddCommand<GiraffeCommand>("giraffe");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Hidden_Commands")]
|
||||
public Task Should_Skip_Hidden_Commands()
|
||||
{
|
||||
// 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();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Command")]
|
||||
public Task Should_Output_Command_Correctly()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddBranch<CatSettings>("cat", animal =>
|
||||
{
|
||||
animal.SetDescription("Contains settings for a cat.");
|
||||
animal.AddCommand<LionCommand>("lion");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("cat", "--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Leaf")]
|
||||
public Task Should_Output_Leaf_Correctly()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddBranch<CatSettings>("cat", animal =>
|
||||
{
|
||||
animal.SetDescription("Contains settings for a cat.");
|
||||
animal.AddCommand<LionCommand>("lion");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("cat", "lion", "--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Default")]
|
||||
public Task Should_Output_Default_Command_Correctly()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.SetDefaultCommand<LionCommand>();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("RootExamples")]
|
||||
public Task Should_Output_Root_Examples_Defined_On_Root()
|
||||
{
|
||||
// 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");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// 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()
|
||||
{
|
||||
// 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" });
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
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" });
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("CommandExamples")]
|
||||
public Task Should_Only_Output_Command_Examples_Defined_On_Command()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
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" });
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("animal", "--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[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 =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddExample(new[] { "12", "-c", "3" });
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("NoDescription")]
|
||||
public Task Should_Not_Show_Truncated_Command_Table_If_Commands_Are_Missing_Description()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
configurator.AddCommand<NoDescriptionCommand>("bar");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("ArgumentOrder")]
|
||||
public Task Should_List_Arguments_In_Correct_Order()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.SetDefaultCommand<GenericCommand<ArgumentOrderSettings>>();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.SetApplicationName("myapp");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--help");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Injection
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
292
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Pairs.cs
Normal file
292
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Pairs.cs
Normal file
@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Pairs
|
||||
{
|
||||
public sealed class AmbiguousSettings : CommandSettings
|
||||
{
|
||||
[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 DefaultPairDeconstructorSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
public IDictionary<string, int> 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 ReadOnlyDictionarySettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
public IReadOnlyDictionary<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StringIntDeconstructor : PairDeconstuctor<string, string>
|
||||
{
|
||||
protected override (string Key, string Value) Deconstruct(string value)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
[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);
|
||||
});
|
||||
}
|
||||
|
||||
[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");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
677
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Parsing.cs
Normal file
677
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Parsing.cs
Normal file
@ -0,0 +1,677 @@
|
||||
using System;
|
||||
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
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
[UsesVerify]
|
||||
[ExpectationPath("Cli/Parsing")]
|
||||
public sealed class Parsing
|
||||
{
|
||||
[UsesVerify]
|
||||
[ExpectationPath("UnknownCommand")]
|
||||
public sealed class UnknownCommand
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_When_Command_Is_Unknown()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("cat", "14");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Unknown_Command_When_Current_Command_Has_No_Arguments()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<EmptyCommand>("empty");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("empty", "other");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_3")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_When_Command_Followed_By_Argument_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddBranch<CommandSettings>("dog", a =>
|
||||
{
|
||||
a.AddCommand<CatCommand>("cat");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "bat", "14");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_4")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_When_Root_Command_Followed_By_Argument_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddCommand<CatCommand>("cat");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("bat", "14");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_5")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_And_No_Arguments_When_Root_Command_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.WithDefaultCommand<GenericCommand<EmptyCommandSettings>>();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddCommand<GenericCommand<EmptyCommandSettings>>("cat");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("bat");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_6")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_And_No_Arguments_When_Command_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.WithDefaultCommand<GenericCommand<EmptyCommandSettings>>();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddBranch<CommandSettings>("dog", a =>
|
||||
{
|
||||
a.AddCommand<CatCommand>("cat");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "bat");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_7")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_When_Root_Command_After_Argument_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.WithDefaultCommand<GenericCommand<FooCommandSettings>>();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<GenericCommand<BarCommandSettings>>("bar");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("qux", "bat");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_8")]
|
||||
public Task Should_Return_Correct_Text_With_Suggestion_When_Command_After_Argument_Is_Unknown_And_Distance_Is_Small()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddBranch<FooCommandSettings>("foo", a =>
|
||||
{
|
||||
a.AddCommand<GenericCommand<BarCommandSettings>>("bar");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("foo", "qux", "bat");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("CannotAssignValueToFlag")]
|
||||
public sealed class CannotAssignValueToFlag
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_For_Long_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "--alive", "foo");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Short_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "-a", "foo");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("NoValueForOption")]
|
||||
public sealed class NoValueForOption
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_For_Long_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "--name");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Short_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "-n");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("NoMatchingArgument")]
|
||||
public sealed class NoMatchingArgument
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<GiraffeCommand>("giraffe");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("giraffe", "foo", "bar", "baz");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("UnexpectedOption")]
|
||||
public sealed class UnexpectedOption
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_For_Long_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--foo");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Short_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("-f");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("UnknownOption")]
|
||||
public sealed class UnknownOption
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_For_Long_Option_If_Strict_Mode_Is_Enabled()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.UseStrictParsing();
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "--unknown");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Short_Option_If_Strict_Mode_Is_Enabled()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.UseStrictParsing();
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "-u");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("UnterminatedQuote")]
|
||||
public sealed class UnterminatedQuote
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("--name", "\"Rufus");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("OptionWithoutName")]
|
||||
public sealed class OptionWithoutName
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text_For_Short_Option()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", "-", " ");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Return_Correct_Text_For_Missing_Long_Option_Value_With_Equality_Separator()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"--foo=");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_3")]
|
||||
public Task Should_Return_Correct_Text_For_Missing_Long_Option_Value_With_Colon_Separator()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"--foo:");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_4")]
|
||||
public Task Should_Return_Correct_Text_For_Missing_Short_Option_Value_With_Equality_Separator()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"-f=");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_5")]
|
||||
public Task Should_Return_Correct_Text_For_Missing_Short_Option_Value_With_Colon_Separator()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"-f:");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("InvalidShortOptionName")]
|
||||
public sealed class InvalidShortOptionName
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"-f0o");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("LongOptionNameIsOneCharacter")]
|
||||
public sealed class LongOptionNameIsOneCharacter
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"--f");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("LongOptionNameIsMissing")]
|
||||
public sealed class LongOptionNameIsMissing
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"-- ");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("LongOptionNameStartWithDigit")]
|
||||
public sealed class LongOptionNameStartWithDigit
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"--1foo");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
[ExpectationPath("LongOptionNameContainSymbol")]
|
||||
public sealed class LongOptionNameContainSymbol
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Return_Correct_Text()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", $"--f€oo");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("--f-oo")]
|
||||
[InlineData("--f-o-o")]
|
||||
[InlineData("--f_oo")]
|
||||
[InlineData("--f_o_o")]
|
||||
public void Should_Allow_Special_Symbols_In_Name(string option)
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("dog", option);
|
||||
|
||||
// Then
|
||||
result.ShouldBe("Error: Command 'dog' is missing required argument 'AGE'.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Quoted_Strings")]
|
||||
public Task Should_Parse_Quoted_Strings_Correctly()
|
||||
{
|
||||
// Given
|
||||
var fixture = new Fixture();
|
||||
fixture.Configure(configurator =>
|
||||
{
|
||||
configurator.AddCommand<DumpRemainingCommand>("foo");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run("foo", "--", "/c", "\"set && pause\"");
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Fixture
|
||||
{
|
||||
private Action<CommandApp> _appConfiguration = _ => { };
|
||||
private Action<IConfigurator> _configuration;
|
||||
|
||||
public void WithDefaultCommand<T>()
|
||||
where T : class, ICommand
|
||||
{
|
||||
_appConfiguration = (app) => app.SetDefaultCommand<T>();
|
||||
}
|
||||
|
||||
public void Configure(Action<IConfigurator> action)
|
||||
{
|
||||
_configuration = action;
|
||||
}
|
||||
|
||||
public string Run(params string[] args)
|
||||
{
|
||||
using (var console = new TestConsole())
|
||||
{
|
||||
var app = new CommandApp();
|
||||
_appConfiguration?.Invoke(app);
|
||||
|
||||
app.Configure(_configuration);
|
||||
app.Configure(c => c.ConfigureConsole(console));
|
||||
app.Run(args);
|
||||
|
||||
return console.Output
|
||||
.NormalizeLineEndings()
|
||||
.TrimLines()
|
||||
.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Remaining
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Register_Remaining_Parsed_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", "--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()
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandApptests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Treat_Commands_As_Case_Sensitive_If_Specified()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
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()
|
||||
{
|
||||
// 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");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Apply_Case_Sensitivity_For_Everything_By_Default()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
|
||||
// When
|
||||
var defaultSensitivity = CaseSensitivity.None;
|
||||
app.Configure(config =>
|
||||
{
|
||||
defaultSensitivity = config.Settings.CaseSensitivity;
|
||||
});
|
||||
|
||||
// Then
|
||||
defaultSensitivity.ShouldBe(CaseSensitivity.All);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class TypeConverters
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Bind_Using_Custom_Type_Converter_If_Specified()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<CatCommand>("cat");
|
||||
});
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
299
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Unsafe.cs
Normal file
299
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Unsafe.cs
Normal file
@ -0,0 +1,299 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Spectre.Console.Cli.Unsafe;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class SafetyOff
|
||||
{
|
||||
[Fact]
|
||||
public void Can_Mix_Safe_And_Unsafe_Configurators()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.SafetyOff().AddBranch("mammal", typeof(MammalSettings), mammal =>
|
||||
{
|
||||
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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
|
||||
config.SafetyOff().AddBranch("animal", typeof(AnimalSettings), animal =>
|
||||
{
|
||||
animal.SafetyOn<AnimalSettings>()
|
||||
.AddBranch<MammalSettings>("mammal", mammal =>
|
||||
{
|
||||
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()
|
||||
{
|
||||
// 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 =>
|
||||
{
|
||||
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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.SafetyOff().AddCommand("dog", typeof(DogCommand));
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// 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));
|
||||
});
|
||||
});
|
||||
|
||||
// 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 =>
|
||||
{
|
||||
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" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Validation
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Attribute_Validation_Fails()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
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...");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
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
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class ValueProviders
|
||||
{
|
||||
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)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Vectors.cs
Normal file
111
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Vectors.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Vectors
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_A_Single_Command_Has_Multiple_Argument_Vectors()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<MultipleArgumentVectorSettings>>("multi");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<MultipleArgumentVectorSpecifiedFirstSettings>>("multi");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// 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[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 });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Version
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Output_The_Version_To_The_Console()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddBranch<MammalSettings>("mammal", mammal =>
|
||||
{
|
||||
mammal.AddCommand<DogCommand>("dog");
|
||||
mammal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.VersionCommand);
|
||||
|
||||
// Then
|
||||
result.Output.ShouldStartWith("Spectre.Cli version ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Xml.cs
Normal file
142
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.Xml.cs
Normal file
@ -0,0 +1,142 @@
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Verify.Extensions;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
[UsesVerify]
|
||||
[ExpectationPath("Cli/Xml")]
|
||||
public sealed class Xml
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Test_1")]
|
||||
public Task Should_Dump_Correct_Model_For_Case_1()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddBranch<MammalSettings>("mammal", mammal =>
|
||||
{
|
||||
mammal.AddCommand<DogCommand>("dog");
|
||||
mammal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.XmlDocCommand);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_2")]
|
||||
public Task Should_Dump_Correct_Model_For_Case_2()
|
||||
{
|
||||
// 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 =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.XmlDocCommand);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_4")]
|
||||
public Task Should_Dump_Correct_Model_For_Case_4()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.XmlDocCommand);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Test_5")]
|
||||
public Task Should_Dump_Correct_Model_For_Case_5()
|
||||
{
|
||||
// Given
|
||||
var fixture = new CommandAppTester();
|
||||
fixture.Configure(config =>
|
||||
{
|
||||
config.AddCommand<OptionVectorCommand>("cmd");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.XmlDocCommand);
|
||||
|
||||
// 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");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = fixture.Run(Constants.XmlDocCommand);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(result.Output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
820
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.cs
Normal file
820
test/Spectre.Console.Tests/Unit/Cli/CommandAppTests.cs
Normal file
@ -0,0 +1,820 @@
|
||||
using System;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Cli;
|
||||
using Spectre.Console.Tests.Data;
|
||||
using Spectre.Console.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit.Cli
|
||||
{
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Pass_Case_1()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddBranch<MammalSettings>("mammal", mammal =>
|
||||
{
|
||||
mammal.AddCommand<DogCommand>("dog");
|
||||
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_Pass_Case_2()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// 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.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
});
|
||||
|
||||
// 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.AddCommand<OptionVectorCommand>("multi");
|
||||
});
|
||||
|
||||
// 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" });
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Be_Able_To_Use_Command_Alias()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<OptionVectorCommand>("multi").WithAlias("multiple");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"multiple", "--foo", "a",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<OptionVectorSettings>().And(vec =>
|
||||
{
|
||||
vec.Foo.Length.ShouldBe(1);
|
||||
vec.Foo.ShouldBe(new[] { "a" });
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Assign_Default_Value_To_Optional_Argument()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<OptionalArgumentWithDefaultValueSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(Array.Empty<string>());
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<OptionalArgumentWithDefaultValueSettings>().And(settings =>
|
||||
{
|
||||
settings.Greeting.ShouldBe("Hello World");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Assign_Property_Initializer_To_Optional_Argument()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<OptionalArgumentWithPropertyInitializerSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(Array.Empty<string>());
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings
|
||||
.ShouldBeOfType<OptionalArgumentWithPropertyInitializerSettings>()
|
||||
.And(settings => settings.Count.ShouldBe(1))
|
||||
.And(settings => settings.Value.ShouldBe(0))
|
||||
.And(settings => settings.Names.ShouldNotBeNull())
|
||||
.And(settings => settings.Names.ShouldNotBeNull())
|
||||
.And(settings => settings.Names.ShouldBeEmpty());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Overwrite_Property_Initializer_With_Argument_Value()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<OptionalArgumentWithPropertyInitializerSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run("-c", "0", "-v", "50", "ABBA", "Herreys");
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings
|
||||
.ShouldBeOfType<OptionalArgumentWithPropertyInitializerSettings>()
|
||||
.And(settings => settings.Count.ShouldBe(0))
|
||||
.And(settings => settings.Value.ShouldBe(50))
|
||||
.And(settings => settings.Names.ShouldContain("ABBA"))
|
||||
.And(settings => settings.Names.ShouldContain("Herreys"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Assign_Default_Value_To_Optional_Argument_Using_Converter_If_Necessary()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<OptionalArgumentWithDefaultValueAndTypeConverterSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(Array.Empty<string>());
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<OptionalArgumentWithDefaultValueAndTypeConverterSettings>().And(settings =>
|
||||
{
|
||||
settings.Greeting.ShouldBe(5);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Required_Argument_Have_Default_Value()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<RequiredArgumentWithDefaultValueSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(Array.Empty<string>()));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
||||
{
|
||||
ex.Message.ShouldBe("The required argument 'GREETING' cannot have a default value.");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Alias_Conflicts_With_Another_Command()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<DogCommand>("dog").WithAlias("cat");
|
||||
config.AddCommand<CatCommand>("cat");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(new[] { "dog", "4", "12" }));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
||||
{
|
||||
ex.Message.ShouldBe("The alias 'cat' for 'dog' conflicts with another command.");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Register_Commands_When_Configuring_Application()
|
||||
{
|
||||
// Given
|
||||
var registrar = new FakeTypeRegistrar();
|
||||
var app = new CommandApp(registrar);
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<GenericCommand<FooCommandSettings>>("foo");
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
app.Run(new[]
|
||||
{
|
||||
"animal", "4", "dog", "12",
|
||||
});
|
||||
|
||||
// Then
|
||||
registrar.Registrations.ContainsKey(typeof(ICommand)).ShouldBeTrue();
|
||||
registrar.Registrations[typeof(ICommand)].ShouldContain(typeof(GenericCommand<FooCommandSettings>));
|
||||
registrar.Registrations[typeof(ICommand)].ShouldContain(typeof(DogCommand));
|
||||
registrar.Registrations[typeof(ICommand)].ShouldContain(typeof(HorseCommand));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Register_Default_Command_When_Configuring_Application()
|
||||
{
|
||||
// Given
|
||||
var registrar = new FakeTypeRegistrar();
|
||||
var app = new CommandApp<DogCommand>(registrar);
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
app.Run(new[]
|
||||
{
|
||||
"12", "4",
|
||||
});
|
||||
|
||||
// Then
|
||||
registrar.Registrations.ContainsKey(typeof(ICommand)).ShouldBeTrue();
|
||||
registrar.Registrations[typeof(ICommand)].ShouldContain(typeof(DogCommand));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_Register_Default_Command_Settings_When_Configuring_Application()
|
||||
{
|
||||
// Given
|
||||
var registrar = new FakeTypeRegistrar();
|
||||
registrar.Register(typeof(DogSettings), typeof(DogSettings));
|
||||
var app = new CommandApp<DogCommand>(registrar);
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
app.Run(new[]
|
||||
{
|
||||
"12", "4",
|
||||
});
|
||||
|
||||
// Then
|
||||
registrar.Registrations.ContainsKey(typeof(DogSettings)).ShouldBeTrue();
|
||||
registrar.Registrations[typeof(DogSettings)].Count.ShouldBe(1);
|
||||
registrar.Registrations[typeof(DogSettings)].ShouldContain(typeof(DogSettings));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_Register_Command_Settings_When_Configuring_Application()
|
||||
{
|
||||
// Given
|
||||
var registrar = new FakeTypeRegistrar();
|
||||
registrar.Register(typeof(DogSettings), typeof(DogSettings));
|
||||
registrar.Register(typeof(MammalSettings), typeof(MammalSettings));
|
||||
var app = new CommandApp(registrar);
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
app.Run(new[]
|
||||
{
|
||||
"animal", "4", "dog", "12",
|
||||
});
|
||||
|
||||
// Then
|
||||
registrar.Registrations.ContainsKey(typeof(DogSettings)).ShouldBeTrue();
|
||||
registrar.Registrations[typeof(DogSettings)].Count.ShouldBe(1);
|
||||
registrar.Registrations[typeof(DogSettings)].ShouldContain(typeof(DogSettings));
|
||||
registrar.Registrations.ContainsKey(typeof(MammalSettings)).ShouldBeTrue();
|
||||
registrar.Registrations[typeof(MammalSettings)].Count.ShouldBe(1);
|
||||
registrar.Registrations[typeof(MammalSettings)].ShouldContain(typeof(MammalSettings));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("true", true)]
|
||||
[InlineData("True", true)]
|
||||
[InlineData("false", false)]
|
||||
[InlineData("False", false)]
|
||||
public void Should_Accept_Explicit_Boolan_Flag(string value, bool expected)
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"dog", "12", "4", "--alive", value,
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
|
||||
{
|
||||
dog.IsAlive.ShouldBe(expected);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_When_Encountering_Unknown_Option_In_Strict_Mode()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.UseStrictParsing();
|
||||
config.AddCommand<DogCommand>("dog");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(new[] { "dog", "--foo" }));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<CommandParseException>().And(ex =>
|
||||
{
|
||||
ex.Message.ShouldBe("Unknown option 'foo'.");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Add_Unknown_Option_To_Remaining_Arguments_In_Relaxed_Mode()
|
||||
{
|
||||
// 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",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.Context.ShouldNotBeNull();
|
||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||
result.Context.ShouldHaveRemainingArgument("foo", values: new[] { "bar" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Add_Unknown_Boolean_Option_To_Remaining_Arguments_In_Relaxed_Mode()
|
||||
{
|
||||
// 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",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.Context.ShouldNotBeNull();
|
||||
result.Context.Remaining.Parsed.Count.ShouldBe(1);
|
||||
result.Context.ShouldHaveRemainingArgument("foo", values: new[] { (string)null });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Be_Able_To_Set_The_Default_Command()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<DogCommand>();
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"4", "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.Name.ShouldBe("Rufus");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Set_Command_Name_In_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",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.Context.ShouldNotBeNull();
|
||||
result.Context.Name.ShouldBe("dog");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Pass_Command_Data_In_Context()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog").WithData(123);
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"animal", "4", "dog", "12",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.Context.ShouldNotBeNull();
|
||||
result.Context.Data.ShouldBe(123);
|
||||
}
|
||||
|
||||
public sealed class Delegate_Commands
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Execute_Delegate_Command_At_Root_Level()
|
||||
{
|
||||
// Given
|
||||
var dog = default(DogSettings);
|
||||
var data = 0;
|
||||
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddDelegate<DogSettings>(
|
||||
"foo", (context, settings) =>
|
||||
{
|
||||
dog = settings;
|
||||
data = (int)context.Data;
|
||||
return 1;
|
||||
}).WithData(2);
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "foo", "4", "12" });
|
||||
|
||||
// Then
|
||||
result.ShouldBe(1);
|
||||
dog.ShouldNotBeNull();
|
||||
dog.Age.ShouldBe(12);
|
||||
dog.Legs.ShouldBe(4);
|
||||
data.ShouldBe(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Execute_Nested_Delegate_Command()
|
||||
{
|
||||
// Given
|
||||
var dog = default(DogSettings);
|
||||
var data = 0;
|
||||
|
||||
var app = new CommandApp();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
config.AddBranch<AnimalSettings>("foo", foo =>
|
||||
{
|
||||
foo.AddDelegate<DogSettings>(
|
||||
"bar", (context, settings) =>
|
||||
{
|
||||
dog = settings;
|
||||
data = (int)context.Data;
|
||||
return 1;
|
||||
}).WithData(2);
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "foo", "4", "bar", "12" });
|
||||
|
||||
// Then
|
||||
result.ShouldBe(1);
|
||||
dog.ShouldNotBeNull();
|
||||
dog.Age.ShouldBe(12);
|
||||
dog.Legs.ShouldBe(4);
|
||||
data.ShouldBe(2);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Remaining_Arguments
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Register_Remaining_Parsed_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", "--foo", "baz",
|
||||
"-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()
|
||||
{
|
||||
// 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",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.Context.Remaining.Raw.Count.ShouldBe(5);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Exception_Handling
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Runtime_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddBranch<AnimalSettings>("animal", animal =>
|
||||
{
|
||||
animal.AddCommand<DogCommand>("dog");
|
||||
animal.AddCommand<HorseCommand>("horse");
|
||||
});
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "animal", "4", "dog", "101", "--name", "Rufus" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Not_Propagate_Exceptions_If_Not_Explicitly_Told_To_Do_So()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.AddCommand<ThrowingCommand>("throw");
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[] { "throw" });
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user