diff --git a/CliFx.Tests/CliApplicationBuilderTests.Commands.cs b/CliFx.Tests/CliApplicationBuilderTests.Commands.cs deleted file mode 100644 index 215af7f..0000000 --- a/CliFx.Tests/CliApplicationBuilderTests.Commands.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests -{ - public partial class CliApplicationBuilderTests - { - [Command] - private class TestCommand : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/CliApplicationBuilderTests.cs b/CliFx.Tests/CliApplicationBuilderTests.cs index 2acca84..3d15a75 100644 --- a/CliFx.Tests/CliApplicationBuilderTests.cs +++ b/CliFx.Tests/CliApplicationBuilderTests.cs @@ -1,12 +1,13 @@ using System; using System.IO; using CliFx.Services; +using CliFx.Tests.TestCommands; using NUnit.Framework; namespace CliFx.Tests { [TestFixture] - public partial class CliApplicationBuilderTests + public class CliApplicationBuilderTests { // Make sure all builder methods work [Test] @@ -17,10 +18,10 @@ namespace CliFx.Tests // Act builder - .AddCommand(typeof(TestCommand)) - .AddCommandsFrom(typeof(TestCommand).Assembly) - .AddCommands(new[] {typeof(TestCommand)}) - .AddCommandsFrom(new[] {typeof(TestCommand).Assembly}) + .AddCommand(typeof(EchoCommand)) + .AddCommandsFrom(typeof(EchoCommand).Assembly) + .AddCommands(new[] {typeof(EchoCommand)}) + .AddCommandsFrom(new[] {typeof(EchoCommand).Assembly}) .AddCommandsFromThisAssembly() .AllowDebugMode() .AllowPreviewMode() diff --git a/CliFx.Tests/CliApplicationTests.Commands.cs b/CliFx.Tests/CliApplicationTests.Commands.cs deleted file mode 100644 index 36f641e..0000000 --- a/CliFx.Tests/CliApplicationTests.Commands.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Exceptions; -using CliFx.Services; - -namespace CliFx.Tests -{ - public partial class CliApplicationTests - { - [Command] - private class DefaultCommand : ICommand - { - public Task ExecuteAsync(IConsole console) - { - console.Output.WriteLine("DefaultCommand executed."); - return Task.CompletedTask; - } - } - - [Command("cmd")] - private class NamedCommand : ICommand - { - public Task ExecuteAsync(IConsole console) - { - console.Output.WriteLine("NamedCommand executed."); - return Task.CompletedTask; - } - } - } - - // Negative - public partial class CliApplicationTests - { - [Command("faulty1")] - private class FaultyCommand1 : ICommand - { - public Task ExecuteAsync(IConsole console) => throw new CommandException(150); - } - - [Command("faulty2")] - private class FaultyCommand2 : ICommand - { - public Task ExecuteAsync(IConsole console) => throw new CommandException("FaultyCommand2 error message.", 150); - } - - [Command("faulty3")] - private class FaultyCommand3 : ICommand - { - public Task ExecuteAsync(IConsole console) => throw new Exception("FaultyCommand3 error message."); - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/CliApplicationTests.cs b/CliFx.Tests/CliApplicationTests.cs index 12378b7..83e20da 100644 --- a/CliFx.Tests/CliApplicationTests.cs +++ b/CliFx.Tests/CliApplicationTests.cs @@ -3,38 +3,39 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests { [TestFixture] - public partial class CliApplicationTests + public class CliApplicationTests { private const string TestVersionText = "v1.0"; private static IEnumerable GetTestCases_RunAsync() { yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, - new string[0], - "DefaultCommand executed." + new[] {typeof(EchoDefaultCommand)}, + new[] {"-m", "foo bar"}, + "foo bar" ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, - new[] {"cmd"}, - "NamedCommand executed." + new[] {typeof(EchoCommand)}, + new[] {"echo", "-m", "foo bar"}, + "foo bar" ); yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoDefaultCommand)}, new[] {"--version"}, TestVersionText ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, + new[] {typeof(EchoCommand)}, new[] {"--version"}, TestVersionText ); @@ -43,78 +44,68 @@ namespace CliFx.Tests private static IEnumerable GetTestCases_RunAsync_Smoke() { yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, - new string[0] - ); - - yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoDefaultCommand)}, new[] {"-h"} ); yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoDefaultCommand)}, new[] {"--help"} ); yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoDefaultCommand)}, new[] {"--version"} ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, + new[] {typeof(EchoCommand)}, new string[0] ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, + new[] {typeof(EchoCommand)}, new[] {"-h"} ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, + new[] {typeof(EchoCommand)}, new[] {"--help"} ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, + new[] {typeof(EchoCommand)}, new[] {"--version"} ); yield return new TestCaseData( - new[] {typeof(NamedCommand)}, - new[] {"cmd", "-h"} + new[] {typeof(EchoCommand)}, + new[] {"echo", "-h"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand1)}, - new[] {"faulty1", "-h"} + new[] {typeof(ExceptionCommand)}, + new[] {"exc", "-h"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand2)}, - new[] {"faulty2", "-h"} + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc", "-h"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand3)}, - new[] {"faulty3", "-h"} - ); - - yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoDefaultCommand)}, new[] {"[preview]"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand1)}, - new[] {"faulty1", "[preview]"} + new[] {typeof(ExceptionCommand)}, + new[] {"exc", "[preview]"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand1)}, - new[] {"faulty1", "[preview]", "-o", "value"} + new[] {typeof(EchoCommand)}, + new[] {"echo", "[preview]", "-o", "value"} ); } @@ -126,23 +117,23 @@ namespace CliFx.Tests ); yield return new TestCaseData( - new[] {typeof(DefaultCommand)}, + new[] {typeof(EchoCommand)}, new[] {"non-existing"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand1)}, - new[] {"faulty1"} + new[] {typeof(ExceptionCommand)}, + new[] {"exc"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand2)}, - new[] {"faulty2"} + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc"} ); yield return new TestCaseData( - new[] {typeof(FaultyCommand3)}, - new[] {"faulty3"} + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc", "-c", "666"} ); } diff --git a/CliFx.Tests/Services/CommandFactoryTests.Commands.cs b/CliFx.Tests/Services/CommandFactoryTests.Commands.cs deleted file mode 100644 index 18544bb..0000000 --- a/CliFx.Tests/Services/CommandFactoryTests.Commands.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests.Services -{ - public partial class CommandFactoryTests - { - [Command] - private class TestCommand : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/CommandFactoryTests.cs b/CliFx.Tests/Services/CommandFactoryTests.cs index f4d4996..9e93725 100644 --- a/CliFx.Tests/Services/CommandFactoryTests.cs +++ b/CliFx.Tests/Services/CommandFactoryTests.cs @@ -3,20 +3,21 @@ using System.Collections.Generic; using System.Linq; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class CommandFactoryTests + public class CommandFactoryTests { private static CommandSchema GetCommandSchema(Type commandType) => new CommandSchemaResolver().GetCommandSchemas(new[] {commandType}).Single(); private static IEnumerable GetTestCases_CreateCommand() { - yield return new TestCaseData(GetCommandSchema(typeof(TestCommand))); + yield return new TestCaseData(GetCommandSchema(typeof(EchoCommand))); } [Test] diff --git a/CliFx.Tests/Services/CommandInitializerTests.Commands.cs b/CliFx.Tests/Services/CommandInitializerTests.Commands.cs deleted file mode 100644 index 88ce29d..0000000 --- a/CliFx.Tests/Services/CommandInitializerTests.Commands.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests.Services -{ - public partial class CommandInitializerTests - { - [Command] - private class TestCommand : ICommand - { - [CommandOption("int", 'i', IsRequired = true)] - public int Option1 { get; set; } = 24; - - [CommandOption("str", 's')] - public string Option2 { get; set; } = "foo bar"; - - [CommandOption('S')] - public bool Option3 { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/CommandInitializerTests.cs b/CliFx.Tests/Services/CommandInitializerTests.cs index 6ff4c45..16d6efe 100644 --- a/CliFx.Tests/Services/CommandInitializerTests.cs +++ b/CliFx.Tests/Services/CommandInitializerTests.cs @@ -4,13 +4,14 @@ using System.Linq; using CliFx.Exceptions; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class CommandInitializerTests + public class CommandInitializerTests { private static CommandSchema GetCommandSchema(Type commandType) => new CommandSchemaResolver().GetCommandSchemas(new[] {commandType}).Single(); @@ -18,63 +19,89 @@ namespace CliFx.Tests.Services private static IEnumerable GetTestCases_InitializeCommand() { yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - new CommandInput(new[] + new DivideCommand(), + GetCommandSchema(typeof(DivideCommand)), + new CommandInput("div", new[] { - new CommandOptionInput("int", "13") + new CommandOptionInput("dividend", "13"), + new CommandOptionInput("divisor", "8") }), - new TestCommand {Option1 = 13} + new DivideCommand {Dividend = 13, Divisor = 8} ); yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - new CommandInput(new[] + new DivideCommand(), + GetCommandSchema(typeof(DivideCommand)), + new CommandInput("div", new[] { - new CommandOptionInput("int", "13"), - new CommandOptionInput("str", "hello world") + new CommandOptionInput("dividend", "13"), + new CommandOptionInput("d", "8") }), - new TestCommand {Option1 = 13, Option2 = "hello world"} + new DivideCommand {Dividend = 13, Divisor = 8} ); yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - new CommandInput(new[] + new DivideCommand(), + GetCommandSchema(typeof(DivideCommand)), + new CommandInput("div", new[] { - new CommandOptionInput("i", "13") + new CommandOptionInput("D", "13"), + new CommandOptionInput("d", "8") }), - new TestCommand {Option1 = 13} + new DivideCommand {Dividend = 13, Divisor = 8} ); yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - new CommandInput(new[] + new ConcatCommand(), + GetCommandSchema(typeof(ConcatCommand)), + new CommandInput("concat", new[] { - new CommandOptionInput("i", "13"), - new CommandOptionInput("s", "hello world"), - new CommandOptionInput("S") + new CommandOptionInput("i", new[] {"foo", " ", "bar"}) }), - new TestCommand {Option1 = 13, Option2 = "hello world", Option3 = true} + new ConcatCommand {Inputs = new[] {"foo", " ", "bar"}} + ); + + yield return new TestCaseData( + new ConcatCommand(), + GetCommandSchema(typeof(ConcatCommand)), + new CommandInput("concat", new[] + { + new CommandOptionInput("i", new[] {"foo", "bar"}), + new CommandOptionInput("s", " ") + }), + new ConcatCommand {Inputs = new[] {"foo", "bar"}, Separator = " "} ); } private static IEnumerable GetTestCases_InitializeCommand_Negative() { yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - CommandInput.Empty + new DivideCommand(), + GetCommandSchema(typeof(DivideCommand)), + new CommandInput("div") ); yield return new TestCaseData( - new TestCommand(), - GetCommandSchema(typeof(TestCommand)), - new CommandInput(new[] + new DivideCommand(), + GetCommandSchema(typeof(DivideCommand)), + new CommandInput("div", new[] { - new CommandOptionInput("str", "hello world") + new CommandOptionInput("D", "13") + }) + ); + + yield return new TestCaseData( + new ConcatCommand(), + GetCommandSchema(typeof(ConcatCommand)), + new CommandInput("concat") + ); + + yield return new TestCaseData( + new ConcatCommand(), + GetCommandSchema(typeof(ConcatCommand)), + new CommandInput("concat", new[] + { + new CommandOptionInput("s", "_") }) ); } diff --git a/CliFx.Tests/Services/CommandOptionInputConverterTests.Types.cs b/CliFx.Tests/Services/CommandOptionInputConverterTests.Types.cs deleted file mode 100644 index ab1c539..0000000 --- a/CliFx.Tests/Services/CommandOptionInputConverterTests.Types.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; - -namespace CliFx.Tests.Services -{ - public partial class CommandOptionInputConverterTests - { - private enum TestEnum - { - Value1, - Value2, - Value3 - } - - private class TestStringConstructable - { - public string Value { get; } - - public TestStringConstructable(string value) - { - Value = value; - } - } - - private class TestStringParseable - { - public string Value { get; } - - private TestStringParseable(string value) - { - Value = value; - } - - public static TestStringParseable Parse(string value) => new TestStringParseable(value); - } - - private class TestStringParseableWithFormatProvider - { - public string Value { get; } - - private TestStringParseableWithFormatProvider(string value) - { - Value = value; - } - - public static TestStringParseableWithFormatProvider Parse(string value, IFormatProvider formatProvider) => - new TestStringParseableWithFormatProvider(value + " " + formatProvider); - } - } - - // Negative - public partial class CommandOptionInputConverterTests - { - private class NonStringParseable - { - public int Value { get; } - - public NonStringParseable(int value) - { - Value = value; - } - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/CommandOptionInputConverterTests.cs b/CliFx.Tests/Services/CommandOptionInputConverterTests.cs index 590ef88..939fbdf 100644 --- a/CliFx.Tests/Services/CommandOptionInputConverterTests.cs +++ b/CliFx.Tests/Services/CommandOptionInputConverterTests.cs @@ -5,13 +5,14 @@ using System.Globalization; using CliFx.Exceptions; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCustomTypes; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class CommandOptionInputConverterTests + public class CommandOptionInputConverterTests { private static IEnumerable GetTestCases_ConvertOptionInput() { @@ -271,7 +272,7 @@ namespace CliFx.Tests.Services yield return new TestCaseData( new CommandOptionInput("option", "123"), - typeof(NonStringParseable) + typeof(TestNonStringParseable) ); } diff --git a/CliFx.Tests/Services/CommandSchemaResolverTests.Commands.cs b/CliFx.Tests/Services/CommandSchemaResolverTests.Commands.cs deleted file mode 100644 index bda2662..0000000 --- a/CliFx.Tests/Services/CommandSchemaResolverTests.Commands.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests.Services -{ - public partial class CommandSchemaResolverTests - { - [Command("cmd", Description = "NormalCommand1 description.")] - private class NormalCommand1 : ICommand - { - [CommandOption("option-a", 'a')] - public int OptionA { get; set; } - - [CommandOption('A')] - public int AlmostOptionA { get; set; } - - [CommandOption("option-b", IsRequired = true)] - public string OptionB { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command(Description = "NormalCommand2 description.")] - private class NormalCommand2 : ICommand - { - [CommandOption("option-c", Description = "OptionC description.")] - public bool OptionC { get; set; } - - [CommandOption("option-d", 'd')] - public DateTimeOffset OptionD { get; set; } - - public string NotAnOption { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } - - // Negative - public partial class CommandSchemaResolverTests - { - [Command("conflict")] - private class ConflictingCommand1 : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command("conflict")] - private class ConflictingCommand2 : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command] - private class InvalidCommand1 - { - } - - // No attribute - private class InvalidCommand2 : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command] - private class InvalidCommand3 : ICommand - { - [CommandOption("conflict")] - public string ConflictingOption1 { get; set; } - - [CommandOption("conflict")] - public string ConflictingOption2 { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command] - private class InvalidCommand4 : ICommand - { - [CommandOption('c')] - public string ConflictingOption1 { get; set; } - - [CommandOption('c')] - public string ConflictingOption2 { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/CommandSchemaResolverTests.cs b/CliFx.Tests/Services/CommandSchemaResolverTests.cs index fb3106d..4959e8b 100644 --- a/CliFx.Tests/Services/CommandSchemaResolverTests.cs +++ b/CliFx.Tests/Services/CommandSchemaResolverTests.cs @@ -3,37 +3,49 @@ using System.Collections.Generic; using CliFx.Exceptions; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class CommandSchemaResolverTests + public class CommandSchemaResolverTests { private static IEnumerable GetTestCases_GetCommandSchemas() { yield return new TestCaseData( - new[] {typeof(NormalCommand1), typeof(NormalCommand2)}, + new[] {typeof(DivideCommand), typeof(ConcatCommand)}, new[] { - new CommandSchema(typeof(NormalCommand1), "cmd", "NormalCommand1 description.", + new CommandSchema(typeof(DivideCommand), "div", "Divide one number by another.", new[] { - new CommandOptionSchema(typeof(NormalCommand1).GetProperty(nameof(NormalCommand1.OptionA)), - "option-a", 'a', false, null), - new CommandOptionSchema(typeof(NormalCommand1).GetProperty(nameof(NormalCommand1.AlmostOptionA)), - null, 'A', false, null), - new CommandOptionSchema(typeof(NormalCommand1).GetProperty(nameof(NormalCommand1.OptionB)), - "option-b", null, true, null) + new CommandOptionSchema(typeof(DivideCommand).GetProperty(nameof(DivideCommand.Dividend)), + "dividend", 'D', true, "The number to divide."), + new CommandOptionSchema(typeof(DivideCommand).GetProperty(nameof(DivideCommand.Divisor)), + "divisor", 'd', true, "The number to divide by.") }), - new CommandSchema(typeof(NormalCommand2), null, "NormalCommand2 description.", + new CommandSchema(typeof(ConcatCommand), "concat", "Concatenate strings.", new[] { - new CommandOptionSchema(typeof(NormalCommand2).GetProperty(nameof(NormalCommand2.OptionC)), - "option-c", null, false, "OptionC description."), - new CommandOptionSchema(typeof(NormalCommand2).GetProperty(nameof(NormalCommand2.OptionD)), - "option-d", 'd', false, null) + new CommandOptionSchema(typeof(ConcatCommand).GetProperty(nameof(ConcatCommand.Inputs)), + null, 'i', true, "Input strings."), + new CommandOptionSchema(typeof(ConcatCommand).GetProperty(nameof(ConcatCommand.Separator)), + null, 's', false, "String separator.") + }) + } + ); + + yield return new TestCaseData( + new[] {typeof(EchoDefaultCommand)}, + new[] + { + new CommandSchema(typeof(EchoDefaultCommand), null, null, + new[] + { + new CommandOptionSchema(typeof(EchoDefaultCommand).GetProperty(nameof(EchoDefaultCommand.Message)), + "message", 'm', true, null) }) } ); @@ -48,27 +60,27 @@ namespace CliFx.Tests.Services yield return new TestCaseData(new object[] { - new[] {typeof(ConflictingCommand1), typeof(ConflictingCommand2)} + new[] {typeof(NonImplementedCommand)} }); yield return new TestCaseData(new object[] { - new[] {typeof(InvalidCommand1)} + new[] {typeof(NonAnnotatedCommand)} + }); + + yield return new TestCaseData(new object[] + { + new[] {typeof(DuplicateOptionNamesCommand)} }); yield return new TestCaseData(new object[] { - new[] {typeof(InvalidCommand2)} + new[] {typeof(DuplicateOptionShortNamesCommand)} }); - + yield return new TestCaseData(new object[] { - new[] {typeof(InvalidCommand3)} - }); - - yield return new TestCaseData(new object[] - { - new[] {typeof(InvalidCommand4)} + new[] {typeof(ExceptionCommand), typeof(CommandExceptionCommand)} }); } diff --git a/CliFx.Tests/Services/DelegateCommandFactoryTests.Commands.cs b/CliFx.Tests/Services/DelegateCommandFactoryTests.Commands.cs deleted file mode 100644 index ff840f2..0000000 --- a/CliFx.Tests/Services/DelegateCommandFactoryTests.Commands.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests.Services -{ - public partial class DelegateCommandFactoryTests - { - [Command] - private class TestCommand : ICommand - { - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/DelegateCommandFactoryTests.cs b/CliFx.Tests/Services/DelegateCommandFactoryTests.cs index a94f430..937bf0a 100644 --- a/CliFx.Tests/Services/DelegateCommandFactoryTests.cs +++ b/CliFx.Tests/Services/DelegateCommandFactoryTests.cs @@ -3,13 +3,14 @@ using System.Collections.Generic; using System.Linq; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class DelegateCommandFactoryTests + public class DelegateCommandFactoryTests { private static CommandSchema GetCommandSchema(Type commandType) => new CommandSchemaResolver().GetCommandSchemas(new[] {commandType}).Single(); @@ -18,7 +19,7 @@ namespace CliFx.Tests.Services { yield return new TestCaseData( new Func(schema => (ICommand) Activator.CreateInstance(schema.Type)), - GetCommandSchema(typeof(TestCommand)) + GetCommandSchema(typeof(EchoCommand)) ); } diff --git a/CliFx.Tests/Services/HelpTextRendererTests.Commands.cs b/CliFx.Tests/Services/HelpTextRendererTests.Commands.cs deleted file mode 100644 index 24a5fc5..0000000 --- a/CliFx.Tests/Services/HelpTextRendererTests.Commands.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Threading.Tasks; -using CliFx.Attributes; -using CliFx.Services; - -namespace CliFx.Tests.Services -{ - public partial class HelpTextRendererTests - { - [Command(Description = "DefaultCommand description.")] - private class DefaultCommand : ICommand - { - [CommandOption("option-a", 'a', Description = "OptionA description.")] - public string OptionA { get; set; } - - [CommandOption("option-b", 'b', Description = "OptionB description.")] - public string OptionB { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command("cmd", Description = "NamedCommand description.")] - private class NamedCommand : ICommand - { - [CommandOption("option-c", 'c', Description = "OptionC description.")] - public string OptionC { get; set; } - - [CommandOption("option-d", 'd', Description = "OptionD description.")] - public string OptionD { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - - [Command("cmd sub", Description = "NamedSubCommand description.")] - private class NamedSubCommand : ICommand - { - [CommandOption("option-e", 'e', Description = "OptionE description.")] - public string OptionE { get; set; } - - public Task ExecuteAsync(IConsole console) => Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/CliFx.Tests/Services/HelpTextRendererTests.cs b/CliFx.Tests/Services/HelpTextRendererTests.cs index 1998045..c05572b 100644 --- a/CliFx.Tests/Services/HelpTextRendererTests.cs +++ b/CliFx.Tests/Services/HelpTextRendererTests.cs @@ -4,13 +4,14 @@ using System.IO; using System.Linq; using CliFx.Models; using CliFx.Services; +using CliFx.Tests.TestCommands; using FluentAssertions; using NUnit.Framework; namespace CliFx.Tests.Services { [TestFixture] - public partial class HelpTextRendererTests + public class HelpTextRendererTests { private static HelpTextSource CreateHelpTextSource(IReadOnlyList availableCommandTypes, Type targetCommandType) { @@ -27,11 +28,13 @@ namespace CliFx.Tests.Services { yield return new TestCaseData( CreateHelpTextSource( - new[] {typeof(DefaultCommand), typeof(NamedCommand), typeof(NamedSubCommand)}, - typeof(DefaultCommand)), + new[] {typeof(HelpDefaultCommand), typeof(HelpNamedCommand), typeof(HelpSubCommand)}, + typeof(HelpDefaultCommand)), new[] { + "Description", + "HelpDefaultCommand description.", "Usage", "[command]", "[options]", "Options", @@ -40,20 +43,20 @@ namespace CliFx.Tests.Services "-h|--help", "Shows help text.", "--version", "Shows version information.", "Commands", - "cmd", "NamedCommand description.", + "cmd", "HelpNamedCommand description.", "You can run", "to show help on a specific command." } ); yield return new TestCaseData( CreateHelpTextSource( - new[] {typeof(DefaultCommand), typeof(NamedCommand), typeof(NamedSubCommand)}, - typeof(NamedCommand)), + new[] {typeof(HelpDefaultCommand), typeof(HelpNamedCommand), typeof(HelpSubCommand)}, + typeof(HelpNamedCommand)), new[] { "Description", - "NamedCommand description.", + "HelpNamedCommand description.", "Usage", "cmd", "[command]", "[options]", "Options", @@ -61,20 +64,20 @@ namespace CliFx.Tests.Services "-d|--option-d", "OptionD description.", "-h|--help", "Shows help text.", "Commands", - "sub", "NamedSubCommand description.", + "sub", "HelpSubCommand description.", "You can run", "to show help on a specific command." } ); yield return new TestCaseData( CreateHelpTextSource( - new[] {typeof(DefaultCommand), typeof(NamedCommand), typeof(NamedSubCommand)}, - typeof(NamedSubCommand)), + new[] {typeof(HelpDefaultCommand), typeof(HelpNamedCommand), typeof(HelpSubCommand)}, + typeof(HelpSubCommand)), new[] { "Description", - "NamedSubCommand description.", + "HelpSubCommand description.", "Usage", "cmd sub", "[options]", "Options", diff --git a/CliFx.Tests/TestCommands/CommandExceptionCommand.cs b/CliFx.Tests/TestCommands/CommandExceptionCommand.cs new file mode 100644 index 0000000..f8a3a5a --- /dev/null +++ b/CliFx.Tests/TestCommands/CommandExceptionCommand.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Exceptions; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("exc")] + public class CommandExceptionCommand : ICommand + { + [CommandOption("code", 'c')] + public int ExitCode { get; set; } = 1337; + + [CommandOption("msg", 'm')] + public string Message { get; set; } + + public Task ExecuteAsync(IConsole console) => throw new CommandException(Message, ExitCode); + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/ConcatCommand.cs b/CliFx.Tests/TestCommands/ConcatCommand.cs new file mode 100644 index 0000000..e357230 --- /dev/null +++ b/CliFx.Tests/TestCommands/ConcatCommand.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("concat", Description = "Concatenate strings.")] + public class ConcatCommand : ICommand + { + [CommandOption('i', IsRequired = true, Description = "Input strings.")] + public IReadOnlyList Inputs { get; set; } + + [CommandOption('s', Description = "String separator.")] + public string Separator { get; set; } = ""; + + public Task ExecuteAsync(IConsole console) + { + console.Output.WriteLine(string.Join(Separator, Inputs)); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/DivideCommand.cs b/CliFx.Tests/TestCommands/DivideCommand.cs new file mode 100644 index 0000000..71dad4e --- /dev/null +++ b/CliFx.Tests/TestCommands/DivideCommand.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("div", Description = "Divide one number by another.")] + public class DivideCommand : ICommand + { + [CommandOption("dividend", 'D', IsRequired = true, Description = "The number to divide.")] + public double Dividend { get; set; } + + [CommandOption("divisor", 'd', IsRequired = true, Description = "The number to divide by.")] + public double Divisor { get; set; } + + // This property should be ignored by resolver + public bool NotAnOption { get; set; } + + public Task ExecuteAsync(IConsole console) + { + console.Output.WriteLine(Dividend / Divisor); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs b/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs new file mode 100644 index 0000000..6dc0a4e --- /dev/null +++ b/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command] + public class DuplicateOptionNamesCommand : ICommand + { + [CommandOption("fruits")] + public string Apples { get; set; } + + [CommandOption("fruits")] + public string Oranges { get; set; } + + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs b/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs new file mode 100644 index 0000000..7c6d65c --- /dev/null +++ b/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command] + public class DuplicateOptionShortNamesCommand : ICommand + { + [CommandOption('f')] + public string Apples { get; set; } + + [CommandOption('f')] + public string Oranges { get; set; } + + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/EchoCommand.cs b/CliFx.Tests/TestCommands/EchoCommand.cs new file mode 100644 index 0000000..56b05ae --- /dev/null +++ b/CliFx.Tests/TestCommands/EchoCommand.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("echo")] + public class EchoCommand : ICommand + { + [CommandOption("message", 'm', IsRequired = true)] + public string Message { get; set; } + + public Task ExecuteAsync(IConsole console) + { + console.Output.WriteLine(Message); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/EchoDefaultCommand.cs b/CliFx.Tests/TestCommands/EchoDefaultCommand.cs new file mode 100644 index 0000000..afc4d4c --- /dev/null +++ b/CliFx.Tests/TestCommands/EchoDefaultCommand.cs @@ -0,0 +1,9 @@ +using CliFx.Attributes; + +namespace CliFx.Tests.TestCommands +{ + [Command] + public class EchoDefaultCommand : EchoCommand + { + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/ExceptionCommand.cs b/CliFx.Tests/TestCommands/ExceptionCommand.cs new file mode 100644 index 0000000..59ab4bf --- /dev/null +++ b/CliFx.Tests/TestCommands/ExceptionCommand.cs @@ -0,0 +1,16 @@ +using System; +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("exc")] + public class ExceptionCommand : ICommand + { + [CommandOption("msg", 'm')] + public string Message { get; set; } + + public Task ExecuteAsync(IConsole console) => throw new Exception(Message); + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/HelpDefaultCommand.cs b/CliFx.Tests/TestCommands/HelpDefaultCommand.cs new file mode 100644 index 0000000..638c309 --- /dev/null +++ b/CliFx.Tests/TestCommands/HelpDefaultCommand.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command(Description = "HelpDefaultCommand description.")] + public class HelpDefaultCommand : ICommand + { + [CommandOption("option-a", 'a', Description = "OptionA description.")] + public string OptionA { get; set; } + + [CommandOption("option-b", 'b', Description = "OptionB description.")] + public string OptionB { get; set; } + + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/HelpNamedCommand.cs b/CliFx.Tests/TestCommands/HelpNamedCommand.cs new file mode 100644 index 0000000..72a2122 --- /dev/null +++ b/CliFx.Tests/TestCommands/HelpNamedCommand.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("cmd", Description = "HelpNamedCommand description.")] + public class HelpNamedCommand : ICommand + { + [CommandOption("option-c", 'c', Description = "OptionC description.")] + public string OptionC { get; set; } + + [CommandOption("option-d", 'd', Description = "OptionD description.")] + public string OptionD { get; set; } + + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/HelpSubCommand.cs b/CliFx.Tests/TestCommands/HelpSubCommand.cs new file mode 100644 index 0000000..fec6df8 --- /dev/null +++ b/CliFx.Tests/TestCommands/HelpSubCommand.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using CliFx.Attributes; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + [Command("cmd sub", Description = "HelpSubCommand description.")] + public class HelpSubCommand : ICommand + { + [CommandOption("option-e", 'e', Description = "OptionE description.")] + public string OptionE { get; set; } + + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs b/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs new file mode 100644 index 0000000..6977532 --- /dev/null +++ b/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using CliFx.Services; + +namespace CliFx.Tests.TestCommands +{ + public class NonAnnotatedCommand : ICommand + { + public Task ExecuteAsync(IConsole console) => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/NonImplementedCommand.cs b/CliFx.Tests/TestCommands/NonImplementedCommand.cs new file mode 100644 index 0000000..a21047d --- /dev/null +++ b/CliFx.Tests/TestCommands/NonImplementedCommand.cs @@ -0,0 +1,9 @@ +using CliFx.Attributes; + +namespace CliFx.Tests.TestCommands +{ + [Command] + public class NonImplementedCommand + { + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCustomTypes/TestEnum.cs b/CliFx.Tests/TestCustomTypes/TestEnum.cs new file mode 100644 index 0000000..95d121b --- /dev/null +++ b/CliFx.Tests/TestCustomTypes/TestEnum.cs @@ -0,0 +1,9 @@ +namespace CliFx.Tests.TestCustomTypes +{ + public enum TestEnum + { + Value1, + Value2, + Value3 + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCustomTypes/TestNonStringParseable.cs b/CliFx.Tests/TestCustomTypes/TestNonStringParseable.cs new file mode 100644 index 0000000..8162902 --- /dev/null +++ b/CliFx.Tests/TestCustomTypes/TestNonStringParseable.cs @@ -0,0 +1,12 @@ +namespace CliFx.Tests.TestCustomTypes +{ + public class TestNonStringParseable + { + public int Value { get; } + + public TestNonStringParseable(int value) + { + Value = value; + } + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCustomTypes/TestStringConstructable.cs b/CliFx.Tests/TestCustomTypes/TestStringConstructable.cs new file mode 100644 index 0000000..8e03f20 --- /dev/null +++ b/CliFx.Tests/TestCustomTypes/TestStringConstructable.cs @@ -0,0 +1,12 @@ +namespace CliFx.Tests.TestCustomTypes +{ + public class TestStringConstructable + { + public string Value { get; } + + public TestStringConstructable(string value) + { + Value = value; + } + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCustomTypes/TestStringParseable.cs b/CliFx.Tests/TestCustomTypes/TestStringParseable.cs new file mode 100644 index 0000000..6682e2b --- /dev/null +++ b/CliFx.Tests/TestCustomTypes/TestStringParseable.cs @@ -0,0 +1,14 @@ +namespace CliFx.Tests.TestCustomTypes +{ + public class TestStringParseable + { + public string Value { get; } + + private TestStringParseable(string value) + { + Value = value; + } + + public static TestStringParseable Parse(string value) => new TestStringParseable(value); + } +} \ No newline at end of file diff --git a/CliFx.Tests/TestCustomTypes/TestStringParseableWithFormatProvider.cs b/CliFx.Tests/TestCustomTypes/TestStringParseableWithFormatProvider.cs new file mode 100644 index 0000000..27d7eeb --- /dev/null +++ b/CliFx.Tests/TestCustomTypes/TestStringParseableWithFormatProvider.cs @@ -0,0 +1,17 @@ +using System; + +namespace CliFx.Tests.TestCustomTypes +{ + public class TestStringParseableWithFormatProvider + { + public string Value { get; } + + private TestStringParseableWithFormatProvider(string value) + { + Value = value; + } + + public static TestStringParseableWithFormatProvider Parse(string value, IFormatProvider formatProvider) => + new TestStringParseableWithFormatProvider(value + " " + formatProvider); + } +} \ No newline at end of file diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index 02d3b42..6729762 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -129,7 +129,7 @@ namespace CliFx // Keep track whether there was an error in the input var isError = false; - // If target command isn't defined, find its parent + // If target command isn't defined, find its contextual replacement if (targetCommandSchema == null) { // If command was specified, inform the user that it's not defined diff --git a/CliFx/Services/ICommandFactory.cs b/CliFx/Services/ICommandFactory.cs index 8258639..e6d1084 100644 --- a/CliFx/Services/ICommandFactory.cs +++ b/CliFx/Services/ICommandFactory.cs @@ -1,5 +1,4 @@ -using System; -using CliFx.Models; +using CliFx.Models; namespace CliFx.Services {