diff --git a/src/SeqCli/Cli/CommandAttribute.cs b/src/SeqCli/Cli/CommandAttribute.cs index a2b29b0b..81199286 100644 --- a/src/SeqCli/Cli/CommandAttribute.cs +++ b/src/SeqCli/Cli/CommandAttribute.cs @@ -20,6 +20,7 @@ namespace SeqCli.Cli public class CommandAttribute : Attribute, ICommandMetadata { public string Name { get; } + public string SubCommand { get; } public string HelpText { get; } public string Example { get; set; } @@ -29,5 +30,10 @@ public CommandAttribute(string name, string helpText) Name = name; HelpText = helpText; } + + public CommandAttribute(string name, string subCommand, string helpText) : this(name, helpText) + { + SubCommand = subCommand; + } } } diff --git a/src/SeqCli/Cli/CommandLineHost.cs b/src/SeqCli/Cli/CommandLineHost.cs index 2b635f1c..bc725e3c 100644 --- a/src/SeqCli/Cli/CommandLineHost.cs +++ b/src/SeqCli/Cli/CommandLineHost.cs @@ -38,10 +38,12 @@ public async Task Run(string[] args) if (args.Length > 0) { var norm = args[0].ToLowerInvariant(); - var cmd = _availableCommands.SingleOrDefault(c => c.Metadata.Name == norm); + var subCommandNorm = args.Length > 1 && !args[1].Contains("-") ? args[1].ToLowerInvariant() : default; + var cmd = _availableCommands.SingleOrDefault(c => c.Metadata.Name == norm && c.Metadata.SubCommand == subCommandNorm); if (cmd != null) { - return await cmd.Value.Value.Invoke(args.Skip(1).ToArray()); + var amountToSkip = subCommandNorm == default ? 1 : 2; + return await cmd.Value.Value.Invoke(args.Skip(amountToSkip).ToArray()); } } diff --git a/src/SeqCli/Cli/CommandMetadata.cs b/src/SeqCli/Cli/CommandMetadata.cs index acf71400..f1bd8fe7 100644 --- a/src/SeqCli/Cli/CommandMetadata.cs +++ b/src/SeqCli/Cli/CommandMetadata.cs @@ -17,6 +17,7 @@ namespace SeqCli.Cli public class CommandMetadata : ICommandMetadata { public string Name { get; set; } + public string SubCommand { get; set; } public string HelpText { get; set; } public string Example { get; set; } } diff --git a/src/SeqCli/Cli/ICommandMetadata.cs b/src/SeqCli/Cli/ICommandMetadata.cs index b5f653d5..7d4d0c4b 100644 --- a/src/SeqCli/Cli/ICommandMetadata.cs +++ b/src/SeqCli/Cli/ICommandMetadata.cs @@ -17,6 +17,7 @@ namespace SeqCli.Cli interface ICommandMetadata { string Name { get; } + string SubCommand { get; } string HelpText { get; } } } diff --git a/test/SeqCli.Tests/Cli/CommandLineHostTests.cs b/test/SeqCli.Tests/Cli/CommandLineHostTests.cs new file mode 100644 index 00000000..049c24df --- /dev/null +++ b/test/SeqCli.Tests/Cli/CommandLineHostTests.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac.Features.Metadata; +using SeqCli.Cli; +using SeqCli.Cli.Commands; +using Xunit; + +namespace SeqCli.Tests.Cli +{ + public class CommandLineHostTests + { + [Fact] + public async Task CheckCommandLineHostPicksCorrectCommand() + { + var commandsRan = new List(); + var availableCommands = new List, CommandMetadata>> + { + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test"))), + new CommandMetadata() {Name = "test"}), + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test2"))), + new CommandMetadata() {Name = "test2"}) + }; + var commandLineHost = new CommandLineHost(availableCommands); + await commandLineHost.Run(new []{ "test"}); + + Assert.Equal(commandsRan.First(), "test"); + } + + [Fact] + public async Task WhenCommandAndSubcommandAndTheUserRunsWithoutSubcommandEnsurePickedCorrect() + { + var commandsRan = new List(); + var availableCommands = + new List, CommandMetadata>> + { + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test"))), + new CommandMetadata() {Name = "test"}), + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test-subcommand"))), + new CommandMetadata() {Name = "test", SubCommand = "subcommand"}) + }; + var commandLineHost = new CommandLineHost(availableCommands); + await commandLineHost.Run(new[] { "test" }); + + Assert.Equal(commandsRan.First(), "test"); + } + + [Fact] + public async Task WhenCommandAndSubcommandAndTheUserRunsWithSubcommandEnsurePickedCorrect() + { + var commandsRan = new List(); + var availableCommands = + new List, CommandMetadata>> + { + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test"))), + new CommandMetadata() {Name = "test"}), + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test-subcommand"))), + new CommandMetadata() {Name = "test", SubCommand = "subcommand"}) + }; + var commandLineHost = new CommandLineHost(availableCommands); + await commandLineHost.Run(new[] { "test", "subcommand" }); + + Assert.Equal(commandsRan.First(), "test-subcommand"); + } + + [Fact] + public async Task WhenMoreThanOneSubcommandAndTheUserRunsWithSubcommandEnsurePickedCorrect() + { + var commandsRan = new List(); + var availableCommands = + new List, CommandMetadata>> + { + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test-subcommand1"))), + new CommandMetadata() {Name = "test", SubCommand = "subcommand1"}), + new Meta, CommandMetadata>( + new Lazy(() => new ActionCommand(() => commandsRan.Add("test-subcommand2"))), + new CommandMetadata() {Name = "test", SubCommand = "subcommand2"}) + }; + var commandLineHost = new CommandLineHost(availableCommands); + await commandLineHost.Run(new[] { "test", "subcommand2" }); + + Assert.Equal(commandsRan.First(), "test-subcommand2"); + } + + class ActionCommand : Command + { + public ActionCommand(Action action) + { + action.Invoke(); + } + } + } +} diff --git a/test/SeqCli.Tests/Cli/NoDuplicateCommands.cs b/test/SeqCli.Tests/Cli/NoDuplicateCommands.cs new file mode 100644 index 00000000..532ddef5 --- /dev/null +++ b/test/SeqCli.Tests/Cli/NoDuplicateCommands.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using SeqCli.Cli; +using Xunit; + +namespace SeqCli.Tests.Cli +{ + + public class NoDuplicateCommands + { + [Fact] + public void EnsureNoDuplicateCommands() + { + var anyDuplicates = typeof(Command).GetTypeInfo().Assembly.GetExportedTypes() + .Where(t => t.IsAssignableFrom(typeof(Command))) + .Select(t => new {CommandType = t, Attribute = t.GetCustomAttribute()}) + .GroupBy(t => new {t.Attribute.Name, t.Attribute.SubCommand}) + .Any(t => t.Count() > 1); + + Assert.Equal(anyDuplicates, false); + } + } +}