From 7b9553dd22488228fa9329391f1af27dcf5cb324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Luthi?= Date: Thu, 12 Jan 2023 13:12:27 +0100 Subject: [PATCH] Add possibility to set description and/or data for the default command (#1091) --- src/Spectre.Console.Cli/CommandApp.cs | 7 +- src/Spectre.Console.Cli/CommandAppOfT.cs | 32 ++++++- .../Internal/Configuration/Configurator.cs | 3 +- .../DefaultCommandConfigurator.cs | 36 ++++++++ .../Cli/CommandAppTester.cs | 18 +++- .../Unit/CommandAppTests.cs | 86 +++++++++++++------ 6 files changed, 151 insertions(+), 31 deletions(-) create mode 100644 src/Spectre.Console.Cli/Internal/Configuration/DefaultCommandConfigurator.cs diff --git a/src/Spectre.Console.Cli/CommandApp.cs b/src/Spectre.Console.Cli/CommandApp.cs index 8ea2c63..4882fc0 100644 --- a/src/Spectre.Console.Cli/CommandApp.cs +++ b/src/Spectre.Console.Cli/CommandApp.cs @@ -1,3 +1,5 @@ +using Spectre.Console.Cli.Internal.Configuration; + namespace Spectre.Console.Cli; /// @@ -39,10 +41,11 @@ public sealed class CommandApp : ICommandApp /// Sets the default command. /// /// The command type. - public void SetDefaultCommand() + /// A that can be used to configure the default command. + public DefaultCommandConfigurator SetDefaultCommand() where TCommand : class, ICommand { - GetConfigurator().SetDefaultCommand(); + return new DefaultCommandConfigurator(GetConfigurator().SetDefaultCommand()); } /// diff --git a/src/Spectre.Console.Cli/CommandAppOfT.cs b/src/Spectre.Console.Cli/CommandAppOfT.cs index b4a1287..295011e 100644 --- a/src/Spectre.Console.Cli/CommandAppOfT.cs +++ b/src/Spectre.Console.Cli/CommandAppOfT.cs @@ -1,3 +1,5 @@ +using Spectre.Console.Cli.Internal.Configuration; + namespace Spectre.Console.Cli; /// @@ -8,6 +10,7 @@ public sealed class CommandApp : ICommandApp where TDefaultCommand : class, ICommand { private readonly CommandApp _app; + private readonly DefaultCommandConfigurator _defaultCommandConfigurator; /// /// Initializes a new instance of the class. @@ -16,7 +19,7 @@ public sealed class CommandApp : ICommandApp public CommandApp(ITypeRegistrar? registrar = null) { _app = new CommandApp(registrar); - _app.GetConfigurator().SetDefaultCommand(); + _defaultCommandConfigurator = _app.SetDefaultCommand(); } /// @@ -46,5 +49,32 @@ public sealed class CommandApp : ICommandApp public Task RunAsync(IEnumerable args) { return _app.RunAsync(args); + } + + internal Configurator GetConfigurator() + { + return _app.GetConfigurator(); + } + + /// + /// Sets the description of the default command. + /// + /// The default command description. + /// The same instance so that multiple calls can be chained. + public CommandApp WithDescription(string description) + { + _defaultCommandConfigurator.WithDescription(description); + return this; + } + + /// + /// Sets data that will be passed to the command via the . + /// + /// The data to pass to the default command. + /// The same instance so that multiple calls can be chained. + public CommandApp WithData(object data) + { + _defaultCommandConfigurator.WithData(data); + return this; } } \ No newline at end of file diff --git a/src/Spectre.Console.Cli/Internal/Configuration/Configurator.cs b/src/Spectre.Console.Cli/Internal/Configuration/Configurator.cs index 746393c..cd1b42d 100644 --- a/src/Spectre.Console.Cli/Internal/Configuration/Configurator.cs +++ b/src/Spectre.Console.Cli/Internal/Configuration/Configurator.cs @@ -25,11 +25,12 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig Examples.Add(args); } - public void SetDefaultCommand() + public ConfiguredCommand SetDefaultCommand() where TDefaultCommand : class, ICommand { DefaultCommand = ConfiguredCommand.FromType( CliConstants.DefaultCommandName, isDefaultCommand: true); + return DefaultCommand; } public ICommandConfigurator AddCommand(string name) diff --git a/src/Spectre.Console.Cli/Internal/Configuration/DefaultCommandConfigurator.cs b/src/Spectre.Console.Cli/Internal/Configuration/DefaultCommandConfigurator.cs new file mode 100644 index 0000000..a11432b --- /dev/null +++ b/src/Spectre.Console.Cli/Internal/Configuration/DefaultCommandConfigurator.cs @@ -0,0 +1,36 @@ +namespace Spectre.Console.Cli.Internal.Configuration; + +/// +/// Fluent configurator for the default command. +/// +public sealed class DefaultCommandConfigurator +{ + private readonly ConfiguredCommand _defaultCommand; + + internal DefaultCommandConfigurator(ConfiguredCommand defaultCommand) + { + _defaultCommand = defaultCommand; + } + + /// + /// Sets the description of the default command. + /// + /// The default command description. + /// The same instance so that multiple calls can be chained. + public DefaultCommandConfigurator WithDescription(string description) + { + _defaultCommand.Description = description; + return this; + } + + /// + /// Sets data that will be passed to the command via the . + /// + /// The data to pass to the default command. + /// The same instance so that multiple calls can be chained. + public DefaultCommandConfigurator WithData(object data) + { + _defaultCommand.Data = data; + return this; + } +} \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs index 8143e1c..d06ccd4 100644 --- a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs +++ b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs @@ -25,11 +25,25 @@ public sealed class CommandAppTester /// /// Sets the default command. /// + /// The optional default command description. + /// The optional default command data. /// The default command type. - public void SetDefaultCommand() + public void SetDefaultCommand(string? description = null, object? data = null) where T : class, ICommand { - _appConfiguration = (app) => app.SetDefaultCommand(); + _appConfiguration = (app) => + { + var defaultCommandBuilder = app.SetDefaultCommand(); + if (description != null) + { + defaultCommandBuilder.WithDescription(description); + } + + if (data != null) + { + defaultCommandBuilder.WithData(data); + } + }; } /// diff --git a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs index 9021b3c..2f69a6b 100644 --- a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs +++ b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs @@ -845,30 +845,6 @@ public sealed partial class CommandAppTests 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(); - - // When - var result = app.Run(new[] - { - "4", "12", "--good-boy", "--name", "Rufus", - }); - - // Then - result.ExitCode.ShouldBe(0); - result.Settings.ShouldBeOfType().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() { @@ -917,6 +893,66 @@ public sealed partial class CommandAppTests // Then result.Context.ShouldNotBeNull(); result.Context.Data.ShouldBe(123); + } + + public sealed class Default_Command + { + [Fact] + public void Should_Be_Able_To_Set_The_Default_Command() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand(); + + // When + var result = app.Run(new[] + { + "4", "12", "--good-boy", "--name", "Rufus", + }); + + // Then + result.ExitCode.ShouldBe(0); + result.Settings.ShouldBeOfType().And(dog => + { + dog.Legs.ShouldBe(4); + dog.Age.ShouldBe(12); + dog.GoodBoy.ShouldBe(true); + dog.Name.ShouldBe("Rufus"); + }); + } + + [Fact] + public void Should_Set_The_Default_Command_Description_Data_CommandApp() + { + // Given + var app = new CommandApp(); + app.SetDefaultCommand() + .WithDescription("The default command") + .WithData(new string[] { "foo", "bar" }); + + // When + + // Then + app.GetConfigurator().DefaultCommand.ShouldNotBeNull(); + app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command"); + app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" }); + } + + [Fact] + public void Should_Set_The_Default_Command_Description_Data_CommandAppOfT() + { + // Given + var app = new CommandApp() + .WithDescription("The default command") + .WithData(new string[] { "foo", "bar" }); + + // When + + // Then + app.GetConfigurator().DefaultCommand.ShouldNotBeNull(); + app.GetConfigurator().DefaultCommand.Description.ShouldBe("The default command"); + app.GetConfigurator().DefaultCommand.Data.ShouldBe(new string[] { "foo", "bar" }); + } } public sealed class Delegate_Commands @@ -930,7 +966,7 @@ public sealed partial class CommandAppTests var app = new CommandApp(); app.Configure(config => - { + { config.PropagateExceptions(); config.AddDelegate( "foo", (context, settings) =>