Alias for command branches (#411)

This commit is contained in:
Ilya Hryapko 2023-02-09 17:26:06 +03:00 committed by GitHub
parent f4183e0462
commit 04610cf492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 288 additions and 189 deletions

View File

@ -88,12 +88,12 @@ public static class ConfiguratorExtensions
configurator.Settings.StrictParsing = true; configurator.Settings.StrictParsing = true;
return configurator; return configurator;
} }
/// <summary> /// <summary>
/// Tells the help writer whether or not to trim trailing period. /// Tells the help writer whether or not to trim trailing period.
/// </summary> /// </summary>
/// <param name="configurator">The configurator.</param> /// <param name="configurator">The configurator.</param>
/// <param name="trimTrailingPeriods">True to trim trailing period (default), false to not.</param> /// <param name="trimTrailingPeriods">True to trim trailing period (default), false to not.</param>
/// <returns>A configurator that can be used to configure the application further.</returns> /// <returns>A configurator that can be used to configure the application further.</returns>
public static IConfigurator TrimTrailingPeriods(this IConfigurator configurator, bool trimTrailingPeriods) public static IConfigurator TrimTrailingPeriods(this IConfigurator configurator, bool trimTrailingPeriods)
@ -181,7 +181,8 @@ public static class ConfiguratorExtensions
/// <param name="configurator">The configurator.</param> /// <param name="configurator">The configurator.</param>
/// <param name="name">The name of the command branch.</param> /// <param name="name">The name of the command branch.</param>
/// <param name="action">The command branch configuration.</param> /// <param name="action">The command branch configuration.</param>
public static void AddBranch( /// <returns>A branch configurator that can be used to configure the branch further.</returns>
public static IBranchConfigurator AddBranch(
this IConfigurator configurator, this IConfigurator configurator,
string name, string name,
Action<IConfigurator<CommandSettings>> action) Action<IConfigurator<CommandSettings>> action)
@ -191,7 +192,7 @@ public static class ConfiguratorExtensions
throw new ArgumentNullException(nameof(configurator)); throw new ArgumentNullException(nameof(configurator));
} }
configurator.AddBranch(name, action); return configurator.AddBranch(name, action);
} }
/// <summary> /// <summary>
@ -201,7 +202,8 @@ public static class ConfiguratorExtensions
/// <param name="configurator">The configurator.</param> /// <param name="configurator">The configurator.</param>
/// <param name="name">The name of the command branch.</param> /// <param name="name">The name of the command branch.</param>
/// <param name="action">The command branch configuration.</param> /// <param name="action">The command branch configuration.</param>
public static void AddBranch<TSettings>( /// <returns>A branch configurator that can be used to configure the branch further.</returns>
public static IBranchConfigurator AddBranch<TSettings>(
this IConfigurator<TSettings> configurator, this IConfigurator<TSettings> configurator,
string name, string name,
Action<IConfigurator<TSettings>> action) Action<IConfigurator<TSettings>> action)
@ -212,7 +214,7 @@ public static class ConfiguratorExtensions
throw new ArgumentNullException(nameof(configurator)); throw new ArgumentNullException(nameof(configurator));
} }
configurator.AddBranch(name, action); return configurator.AddBranch(name, action);
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,14 @@
namespace Spectre.Console.Cli;
/// <summary>
/// Represents a branch configurator.
/// </summary>
public interface IBranchConfigurator
{
/// <summary>
/// Adds an alias (an alternative name) to the branch being configured.
/// </summary>
/// <param name="name">The alias to add to the branch being configured.</param>
/// <returns>The same <see cref="IBranchConfigurator"/> instance so that multiple calls can be chained.</returns>
IBranchConfigurator WithAlias(string name);
}

View File

@ -41,6 +41,7 @@ public interface IConfigurator
/// <typeparam name="TSettings">The command setting type.</typeparam> /// <typeparam name="TSettings">The command setting type.</typeparam>
/// <param name="name">The name of the command branch.</param> /// <param name="name">The name of the command branch.</param>
/// <param name="action">The command branch configurator.</param> /// <param name="action">The command branch configurator.</param>
void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action) /// <returns>A branch configurator that can be used to configure the branch further.</returns>
IBranchConfigurator AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
where TSettings : CommandSettings; where TSettings : CommandSettings;
} }

View File

@ -51,6 +51,7 @@ public interface IConfigurator<in TSettings>
/// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam> /// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam>
/// <param name="name">The name of the command branch.</param> /// <param name="name">The name of the command branch.</param>
/// <param name="action">The command branch configuration.</param> /// <param name="action">The command branch configuration.</param>
void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action) /// <returns>A branch configurator that can be used to configure the branch further.</returns>
IBranchConfigurator AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
where TDerivedSettings : TSettings; where TDerivedSettings : TSettings;
} }

View File

@ -0,0 +1,17 @@
namespace Spectre.Console.Cli;
internal sealed class BranchConfigurator : IBranchConfigurator
{
public ConfiguredCommand Command { get; }
public BranchConfigurator(ConfiguredCommand command)
{
Command = command;
}
public IBranchConfigurator WithAlias(string alias)
{
Command.Aliases.Add(alias);
return this;
}
}

View File

@ -48,12 +48,13 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig
return new CommandConfigurator(command); return new CommandConfigurator(command);
} }
public void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action) public IBranchConfigurator AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
where TSettings : CommandSettings where TSettings : CommandSettings
{ {
var command = ConfiguredCommand.FromBranch<TSettings>(name); var command = ConfiguredCommand.FromBranch<TSettings>(name);
action(new Configurator<TSettings>(command, _registrar)); action(new Configurator<TSettings>(command, _registrar));
Commands.Add(command); var added = Commands.AddAndReturn(command);
return new BranchConfigurator(added);
} }
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
@ -74,7 +75,7 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig
return result; return result;
} }
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action) IBranchConfigurator IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
{ {
var command = ConfiguredCommand.FromBranch(settings, name); var command = ConfiguredCommand.FromBranch(settings, name);
@ -86,6 +87,7 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig
} }
action(configurator); action(configurator);
Commands.Add(command); var added = Commands.AddAndReturn(command);
return new BranchConfigurator(added);
} }
} }

View File

@ -47,12 +47,13 @@ internal sealed class Configurator<TSettings> : IUnsafeBranchConfigurator, IConf
return new CommandConfigurator(command); return new CommandConfigurator(command);
} }
public void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action) public IBranchConfigurator AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
where TDerivedSettings : TSettings where TDerivedSettings : TSettings
{ {
var command = ConfiguredCommand.FromBranch<TDerivedSettings>(name); var command = ConfiguredCommand.FromBranch<TDerivedSettings>(name);
action(new Configurator<TDerivedSettings>(command, _registrar)); action(new Configurator<TDerivedSettings>(command, _registrar));
_command.Children.Add(command); var added = _command.Children.AddAndReturn(command);
return new BranchConfigurator(added);
} }
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
@ -73,7 +74,7 @@ internal sealed class Configurator<TSettings> : IUnsafeBranchConfigurator, IConf
return result; return result;
} }
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action) IBranchConfigurator IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
{ {
var command = ConfiguredCommand.FromBranch(settings, name); var command = ConfiguredCommand.FromBranch(settings, name);
@ -85,6 +86,7 @@ internal sealed class Configurator<TSettings> : IUnsafeBranchConfigurator, IConf
} }
action(configurator); action(configurator);
_command.Children.Add(command); var added = _command.Children.AddAndReturn(command);
return new BranchConfigurator(added);
} }
} }

View File

@ -19,5 +19,6 @@ public interface IUnsafeConfigurator
/// <param name="name">The name of the command branch.</param> /// <param name="name">The name of the command branch.</param>
/// <param name="settings">The command setting type.</param> /// <param name="settings">The command setting type.</param>
/// <param name="action">The command branch configurator.</param> /// <param name="action">The command branch configurator.</param>
void AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action); /// <returns>A branch configurator that can be used to configure the branch further.</returns>
IBranchConfigurator AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action);
} }

View File

@ -132,8 +132,8 @@ public sealed partial class CommandAppTests
dog.IsAlive.ShouldBe(false); dog.IsAlive.ShouldBe(false);
dog.Name.ShouldBe("Rufus"); dog.Name.ShouldBe("Rufus");
}); });
} }
[Fact] [Fact]
public void Should_Pass_Case_5() public void Should_Pass_Case_5()
{ {
@ -165,7 +165,7 @@ public sealed partial class CommandAppTests
dog.IsAlive.ShouldBe(true); dog.IsAlive.ShouldBe(true);
dog.Name.ShouldBe("Rufus"); dog.Name.ShouldBe("Rufus");
}); });
} }
[Fact] [Fact]
public void Should_Pass_Case_6() public void Should_Pass_Case_6()
@ -237,10 +237,10 @@ public sealed partial class CommandAppTests
var result = app.Run(new[] var result = app.Run(new[]
{ {
"dog", "12", "4", "dog", "12", "4",
"--name=\" -Rufus --' ", "--name=\" -Rufus --' ",
"--", "--",
"--order-by", "\"-size\"", "--order-by", "\"-size\"",
"--order-by", " ", "--order-by", " ",
"--order-by", string.Empty, "--order-by", string.Empty,
}); });
@ -249,8 +249,8 @@ public sealed partial class CommandAppTests
result.Settings.ShouldBeOfType<DogSettings>().And(dog => result.Settings.ShouldBeOfType<DogSettings>().And(dog =>
{ {
dog.Name.ShouldBe("\" -Rufus --' "); dog.Name.ShouldBe("\" -Rufus --' ");
}); });
result.Context.Remaining.Parsed.Count.ShouldBe(1); result.Context.Remaining.Parsed.Count.ShouldBe(1);
result.Context.ShouldHaveRemainingArgument("order-by", values: new[] { "\"-size\"", " ", string.Empty }); result.Context.ShouldHaveRemainingArgument("order-by", values: new[] { "\"-size\"", " ", string.Empty });
} }
@ -280,6 +280,65 @@ public sealed partial class CommandAppTests
}); });
} }
[Fact]
public void Should_Be_Able_To_Use_Branch_Alias()
{
// Given
var app = new CommandAppTester();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
}).WithAlias("a");
});
// When
var result = app.Run(new[]
{
"a", "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_Throw_If_Branch_Alias_Conflicts_With_Another_Command()
{
// Given
var app = new CommandApp();
app.Configure(config =>
{
config.PropagateExceptions();
config.AddCommand<DogCommand>("a");
config.AddBranch<AnimalSettings>("animal", animal =>
{
animal.AddCommand<DogCommand>("dog");
animal.AddCommand<HorseCommand>("horse");
}).WithAlias("a");
});
// When
var result = Record.Exception(() => app.Run(new[] { "a", "0", "12" }));
// Then
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
{
ex.Message.ShouldBe("The alias 'a' for 'animal' conflicts with another command.");
});
}
[Fact] [Fact]
public void Should_Assign_Default_Value_To_Optional_Argument() public void Should_Assign_Default_Value_To_Optional_Argument()
{ {
@ -554,181 +613,181 @@ public sealed partial class CommandAppTests
{ {
dog.IsAlive.ShouldBe(expected); dog.IsAlive.ShouldBe(expected);
}); });
} }
[Fact] [Fact]
public void Should_Set_Short_Option_Before_Argument() public void Should_Set_Short_Option_Before_Argument()
{ {
// Given // Given
var app = new CommandAppTester(); var app = new CommandAppTester();
app.Configure(config => app.Configure(config =>
{ {
config.PropagateExceptions(); config.PropagateExceptions();
config.AddCommand<DogCommand>("dog"); config.AddCommand<DogCommand>("dog");
}); });
// When // When
var result = app.Run(new[] { "dog", "-a", "-n=Rufus", "4", "12", }); var result = app.Run(new[] { "dog", "-a", "-n=Rufus", "4", "12", });
// Then // Then
result.ExitCode.ShouldBe(0); result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(settings => result.Settings.ShouldBeOfType<DogSettings>().And(settings =>
{ {
settings.IsAlive.ShouldBeTrue(); settings.IsAlive.ShouldBeTrue();
settings.Name.ShouldBe("Rufus"); settings.Name.ShouldBe("Rufus");
settings.Legs.ShouldBe(4); settings.Legs.ShouldBe(4);
settings.Age.ShouldBe(12); settings.Age.ShouldBe(12);
}); });
} }
[Theory] [Theory]
[InlineData("true", true)] [InlineData("true", true)]
[InlineData("True", true)] [InlineData("True", true)]
[InlineData("false", false)] [InlineData("false", false)]
[InlineData("False", false)] [InlineData("False", false)]
public void Should_Set_Short_Option_With_Explicit_Boolan_Flag_Before_Argument(string value, bool expected) public void Should_Set_Short_Option_With_Explicit_Boolan_Flag_Before_Argument(string value, bool expected)
{ {
// Given // Given
var app = new CommandAppTester(); var app = new CommandAppTester();
app.Configure(config => app.Configure(config =>
{ {
config.PropagateExceptions(); config.PropagateExceptions();
config.AddCommand<DogCommand>("dog"); config.AddCommand<DogCommand>("dog");
}); });
// When // When
var result = app.Run(new[] { "dog", "-a", value, "4", "12", }); var result = app.Run(new[] { "dog", "-a", value, "4", "12", });
// Then // Then
result.ExitCode.ShouldBe(0); result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(settings => result.Settings.ShouldBeOfType<DogSettings>().And(settings =>
{ {
settings.IsAlive.ShouldBe(expected); settings.IsAlive.ShouldBe(expected);
settings.Legs.ShouldBe(4); settings.Legs.ShouldBe(4);
settings.Age.ShouldBe(12); settings.Age.ShouldBe(12);
}); });
} }
[Fact] [Fact]
public void Should_Set_Long_Option_Before_Argument() public void Should_Set_Long_Option_Before_Argument()
{ {
// Given // Given
var app = new CommandAppTester(); var app = new CommandAppTester();
app.Configure(config => app.Configure(config =>
{ {
config.PropagateExceptions(); config.PropagateExceptions();
config.AddCommand<DogCommand>("dog"); config.AddCommand<DogCommand>("dog");
}); });
// When // When
var result = app.Run(new[] { "dog", "--alive", "--name=Rufus", "4", "12" }); var result = app.Run(new[] { "dog", "--alive", "--name=Rufus", "4", "12" });
// Then // Then
result.ExitCode.ShouldBe(0); result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(settings => result.Settings.ShouldBeOfType<DogSettings>().And(settings =>
{ {
settings.IsAlive.ShouldBeTrue(); settings.IsAlive.ShouldBeTrue();
settings.Name.ShouldBe("Rufus"); settings.Name.ShouldBe("Rufus");
settings.Legs.ShouldBe(4); settings.Legs.ShouldBe(4);
settings.Age.ShouldBe(12); settings.Age.ShouldBe(12);
}); });
} }
[Theory] [Theory]
[InlineData("true", true)] [InlineData("true", true)]
[InlineData("True", true)] [InlineData("True", true)]
[InlineData("false", false)] [InlineData("false", false)]
[InlineData("False", false)] [InlineData("False", false)]
public void Should_Set_Long_Option_With_Explicit_Boolan_Flag_Before_Argument(string value, bool expected) public void Should_Set_Long_Option_With_Explicit_Boolan_Flag_Before_Argument(string value, bool expected)
{ {
// Given // Given
var app = new CommandAppTester(); var app = new CommandAppTester();
app.Configure(config => app.Configure(config =>
{ {
config.PropagateExceptions(); config.PropagateExceptions();
config.AddCommand<DogCommand>("dog"); config.AddCommand<DogCommand>("dog");
}); });
// When // When
var result = app.Run(new[] { "dog", "--alive", value, "4", "12", }); var result = app.Run(new[] { "dog", "--alive", value, "4", "12", });
// Then // Then
result.ExitCode.ShouldBe(0); result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(settings => result.Settings.ShouldBeOfType<DogSettings>().And(settings =>
{ {
settings.IsAlive.ShouldBe(expected); settings.IsAlive.ShouldBe(expected);
settings.Legs.ShouldBe(4); settings.Legs.ShouldBe(4);
settings.Age.ShouldBe(12); settings.Age.ShouldBe(12);
}); });
} }
[Theory] [Theory]
// Long options // Long options
[InlineData("dog --alive 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog --alive 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog --alive=true 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog --alive=true 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog --alive:true 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog --alive:true 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog --alive --good-boy 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog --alive --good-boy 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog --alive=true --good-boy=true 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog --alive=true --good-boy=true 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog --alive:true --good-boy:true 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog --alive:true --good-boy:true 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog --alive --good-boy --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --alive --good-boy --name Rufus 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog --alive=true --good-boy=true --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --alive=true --good-boy=true --name Rufus 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog --alive:true --good-boy:true --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --alive:true --good-boy:true --name Rufus 4 12", 4, 12, true, true, "Rufus")]
// Short options // Short options
[InlineData("dog -a 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog -a 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog -a=true 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog -a=true 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog -a:true 4 12 --name Rufus", 4, 12, false, true, "Rufus")] [InlineData("dog -a:true 4 12 --name Rufus", 4, 12, false, true, "Rufus")]
[InlineData("dog -a --good-boy 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog -a --good-boy 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog -a=true -g=true 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog -a=true -g=true 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog -a:true -g:true 4 12 --name Rufus", 4, 12, true, true, "Rufus")] [InlineData("dog -a:true -g:true 4 12 --name Rufus", 4, 12, true, true, "Rufus")]
[InlineData("dog -a -g --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog -a -g --name Rufus 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog -a=true -g=true --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog -a=true -g=true --name Rufus 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog -a:true -g:true --name Rufus 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog -a:true -g:true --name Rufus 4 12", 4, 12, true, true, "Rufus")]
// Switch around ordering of the options // Switch around ordering of the options
[InlineData("dog --good-boy:true --name Rufus --alive:true 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --good-boy:true --name Rufus --alive:true 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog --name Rufus --alive:true --good-boy:true 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --name Rufus --alive:true --good-boy:true 4 12", 4, 12, true, true, "Rufus")]
[InlineData("dog --name Rufus --good-boy:true --alive:true 4 12", 4, 12, true, true, "Rufus")] [InlineData("dog --name Rufus --good-boy:true --alive:true 4 12", 4, 12, true, true, "Rufus")]
// Inject the command arguments in between the options // Inject the command arguments in between the options
[InlineData("dog 4 12 --good-boy:true --name Rufus --alive:true", 4, 12, true, true, "Rufus")] [InlineData("dog 4 12 --good-boy:true --name Rufus --alive:true", 4, 12, true, true, "Rufus")]
[InlineData("dog 4 --good-boy:true 12 --name Rufus --alive:true", 4, 12, true, true, "Rufus")] [InlineData("dog 4 --good-boy:true 12 --name Rufus --alive:true", 4, 12, true, true, "Rufus")]
[InlineData("dog --good-boy:true 4 12 --name Rufus --alive:true", 4, 12, true, true, "Rufus")] [InlineData("dog --good-boy:true 4 12 --name Rufus --alive:true", 4, 12, true, true, "Rufus")]
[InlineData("dog --good-boy:true 4 --name Rufus 12 --alive:true", 4, 12, true, true, "Rufus")] [InlineData("dog --good-boy:true 4 --name Rufus 12 --alive:true", 4, 12, true, true, "Rufus")]
[InlineData("dog --name Rufus --alive:true 4 12 --good-boy:true", 4, 12, true, true, "Rufus")] [InlineData("dog --name Rufus --alive:true 4 12 --good-boy:true", 4, 12, true, true, "Rufus")]
[InlineData("dog --name Rufus --alive:true 4 --good-boy:true 12", 4, 12, true, true, "Rufus")] [InlineData("dog --name Rufus --alive:true 4 --good-boy:true 12", 4, 12, true, true, "Rufus")]
// Inject the command arguments in between the options (all flag values set to false) // Inject the command arguments in between the options (all flag values set to false)
[InlineData("dog 4 12 --good-boy:false --name Rufus --alive:false", 4, 12, false, false, "Rufus")] [InlineData("dog 4 12 --good-boy:false --name Rufus --alive:false", 4, 12, false, false, "Rufus")]
[InlineData("dog 4 --good-boy:false 12 --name Rufus --alive:false", 4, 12, false, false, "Rufus")] [InlineData("dog 4 --good-boy:false 12 --name Rufus --alive:false", 4, 12, false, false, "Rufus")]
[InlineData("dog --good-boy:false 4 12 --name Rufus --alive:false", 4, 12, false, false, "Rufus")] [InlineData("dog --good-boy:false 4 12 --name Rufus --alive:false", 4, 12, false, false, "Rufus")]
[InlineData("dog --good-boy:false 4 --name Rufus 12 --alive:false", 4, 12, false, false, "Rufus")] [InlineData("dog --good-boy:false 4 --name Rufus 12 --alive:false", 4, 12, false, false, "Rufus")]
[InlineData("dog --name Rufus --alive:false 4 12 --good-boy:false", 4, 12, false, false, "Rufus")] [InlineData("dog --name Rufus --alive:false 4 12 --good-boy:false", 4, 12, false, false, "Rufus")]
[InlineData("dog --name Rufus --alive:false 4 --good-boy:false 12", 4, 12, false, false, "Rufus")] [InlineData("dog --name Rufus --alive:false 4 --good-boy:false 12", 4, 12, false, false, "Rufus")]
public void Should_Set_Option_Before_Argument(string arguments, int legs, int age, bool goodBoy, bool isAlive, string name) public void Should_Set_Option_Before_Argument(string arguments, int legs, int age, bool goodBoy, bool isAlive, string name)
{ {
// Given // Given
var app = new CommandAppTester(); var app = new CommandAppTester();
app.Configure(config => app.Configure(config =>
{ {
config.PropagateExceptions(); config.PropagateExceptions();
config.AddCommand<DogCommand>("dog"); config.AddCommand<DogCommand>("dog");
}); });
// When // When
var result = app.Run(arguments.Split(' ')); var result = app.Run(arguments.Split(' '));
// Then // Then
result.ExitCode.ShouldBe(0); result.ExitCode.ShouldBe(0);
result.Settings.ShouldBeOfType<DogSettings>().And(settings => result.Settings.ShouldBeOfType<DogSettings>().And(settings =>
{ {
settings.Legs.ShouldBe(legs); settings.Legs.ShouldBe(legs);
settings.Age.ShouldBe(age); settings.Age.ShouldBe(age);
settings.GoodBoy.ShouldBe(goodBoy); settings.GoodBoy.ShouldBe(goodBoy);
settings.IsAlive.ShouldBe(isAlive); settings.IsAlive.ShouldBe(isAlive);
settings.Name.ShouldBe(name); settings.Name.ShouldBe(name);
}); });
} }
[Fact] [Fact]