From 9690c380d38bd767dc0e607caf328f64e3bae469 Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Wed, 13 Nov 2019 20:31:48 +0200 Subject: [PATCH] Use C#8 features and cleanup --- CliFx.Benchmarks/CliFx.Benchmarks.csproj | 1 + CliFx.Benchmarks/Commands/CliFxCommand.cs | 5 +- CliFx.Benchmarks/Commands/CliprCommand.cs | 2 +- .../Commands/CommandLineParserCommand.cs | 2 +- CliFx.Benchmarks/Commands/McMasterCommand.cs | 2 +- CliFx.Benchmarks/Commands/PowerArgsCommand.cs | 2 +- .../Commands/SystemCommandLineCommand.cs | 2 +- CliFx.Demo/CliFx.Demo.csproj | 1 + CliFx.Demo/Commands/BookAddCommand.cs | 3 +- CliFx.Demo/Commands/BookCommand.cs | 3 +- CliFx.Demo/Commands/BookListCommand.cs | 3 +- CliFx.Demo/Commands/BookRemoveCommand.cs | 3 +- CliFx.Demo/Program.cs | 12 +- CliFx.Tests/CliApplicationBuilderTests.cs | 6 +- CliFx.Tests/CliApplicationTests.cs | 213 +++++++++--------- CliFx.Tests/CliFx.Tests.csproj | 1 + .../Services/DelegateCommandFactoryTests.cs | 2 +- CliFx.Tests/Services/HelpTextRendererTests.cs | 17 +- CliFx.Tests/Services/VirtualConsoleTests.cs | 43 ++-- .../TestCommands/CommandExceptionCommand.cs | 5 +- CliFx.Tests/TestCommands/ConcatCommand.cs | 1 - CliFx.Tests/TestCommands/DivideCommand.cs | 3 +- .../DuplicateOptionNamesCommand.cs | 7 +- .../DuplicateOptionShortNamesCommand.cs | 7 +- .../EnvironmentVariableCommand.cs | 5 +- ...onmentVariableWithMultipleValuesCommand.cs | 3 +- ...ariableWithoutCollectionPropertyCommand.cs | 6 +- CliFx.Tests/TestCommands/ExceptionCommand.cs | 3 +- .../TestCommands/HelloWorldDefaultCommand.cs | 3 +- .../TestCommands/HelpDefaultCommand.cs | 7 +- CliFx.Tests/TestCommands/HelpNamedCommand.cs | 7 +- CliFx.Tests/TestCommands/HelpSubCommand.cs | 5 +- .../TestCommands/NonAnnotatedCommand.cs | 3 +- CliFx.Tests/Utilities/ProgressTickerTests.cs | 44 ++-- CliFx/Attributes/CommandAttribute.cs | 8 +- CliFx/Attributes/CommandOptionAttribute.cs | 18 +- CliFx/CliApplication.cs | 24 +- CliFx/CliApplicationBuilder.cs | 56 +++-- CliFx/CliFx.csproj | 8 +- CliFx/Exceptions/CliFxException.cs | 4 +- CliFx/Exceptions/CommandException.cs | 7 +- CliFx/Extensions.cs | 23 +- CliFx/ICliApplicationBuilder.cs | 2 +- CliFx/ICommand.cs | 3 +- CliFx/Internal/Extensions.cs | 9 +- CliFx/Internal/Guards.cs | 13 -- CliFx/Models/ApplicationConfiguration.cs | 3 +- CliFx/Models/ApplicationMetadata.cs | 16 +- CliFx/Models/CommandInput.cs | 23 +- CliFx/Models/CommandOptionInput.cs | 4 +- CliFx/Models/CommandOptionSchema.cs | 25 +- CliFx/Models/CommandSchema.cs | 18 +- CliFx/Models/Extensions.cs | 60 ++--- CliFx/Models/HelpTextSource.cs | 7 +- CliFx/Services/CommandFactory.cs | 7 +- CliFx/Services/CommandInitializer.cs | 20 +- CliFx/Services/CommandInputParser.cs | 8 +- CliFx/Services/CommandOptionInputConverter.cs | 15 +- CliFx/Services/CommandSchemaResolver.cs | 4 +- CliFx/Services/DelegateCommandFactory.cs | 9 +- CliFx/Services/EnvironmentVariablesParser.cs | 7 +- CliFx/Services/Extensions.cs | 35 +-- CliFx/Services/HelpTextRenderer.cs | 25 +- .../Services/ICommandOptionInputConverter.cs | 2 +- CliFx/Services/SystemConsole.cs | 2 +- CliFx/Services/VirtualConsole.cs | 7 +- 66 files changed, 381 insertions(+), 523 deletions(-) delete mode 100644 CliFx/Internal/Guards.cs diff --git a/CliFx.Benchmarks/CliFx.Benchmarks.csproj b/CliFx.Benchmarks/CliFx.Benchmarks.csproj index 8b168cb..62ab854 100644 --- a/CliFx.Benchmarks/CliFx.Benchmarks.csproj +++ b/CliFx.Benchmarks/CliFx.Benchmarks.csproj @@ -3,6 +3,7 @@ Exe netcoreapp3.0 + enable diff --git a/CliFx.Benchmarks/Commands/CliFxCommand.cs b/CliFx.Benchmarks/Commands/CliFxCommand.cs index 3c33aff..2c6481e 100644 --- a/CliFx.Benchmarks/Commands/CliFxCommand.cs +++ b/CliFx.Benchmarks/Commands/CliFxCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,7 +8,7 @@ namespace CliFx.Benchmarks.Commands public class CliFxCommand : ICommand { [CommandOption("str", 's')] - public string StrOption { get; set; } + public string? StrOption { get; set; } [CommandOption("int", 'i')] public int IntOption { get; set; } diff --git a/CliFx.Benchmarks/Commands/CliprCommand.cs b/CliFx.Benchmarks/Commands/CliprCommand.cs index 3a34d74..88c5507 100644 --- a/CliFx.Benchmarks/Commands/CliprCommand.cs +++ b/CliFx.Benchmarks/Commands/CliprCommand.cs @@ -5,7 +5,7 @@ namespace CliFx.Benchmarks.Commands public class CliprCommand { [NamedArgument('s', "str")] - public string StrOption { get; set; } + public string? StrOption { get; set; } [NamedArgument('i', "int")] public int IntOption { get; set; } diff --git a/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs b/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs index 8ffbc1f..9a91f12 100644 --- a/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs +++ b/CliFx.Benchmarks/Commands/CommandLineParserCommand.cs @@ -5,7 +5,7 @@ namespace CliFx.Benchmarks.Commands public class CommandLineParserCommand { [Option('s', "str")] - public string StrOption { get; set; } + public string? StrOption { get; set; } [Option('i', "int")] public int IntOption { get; set; } diff --git a/CliFx.Benchmarks/Commands/McMasterCommand.cs b/CliFx.Benchmarks/Commands/McMasterCommand.cs index 57a15d7..6501290 100644 --- a/CliFx.Benchmarks/Commands/McMasterCommand.cs +++ b/CliFx.Benchmarks/Commands/McMasterCommand.cs @@ -5,7 +5,7 @@ namespace CliFx.Benchmarks.Commands public class McMasterCommand { [Option("--str|-s")] - public string StrOption { get; set; } + public string? StrOption { get; set; } [Option("--int|-i")] public int IntOption { get; set; } diff --git a/CliFx.Benchmarks/Commands/PowerArgsCommand.cs b/CliFx.Benchmarks/Commands/PowerArgsCommand.cs index 003dc2d..2c09e30 100644 --- a/CliFx.Benchmarks/Commands/PowerArgsCommand.cs +++ b/CliFx.Benchmarks/Commands/PowerArgsCommand.cs @@ -5,7 +5,7 @@ namespace CliFx.Benchmarks.Commands public class PowerArgsCommand { [ArgShortcut("--str"), ArgShortcut("-s")] - public string StrOption { get; set; } + public string? StrOption { get; set; } [ArgShortcut("--int"), ArgShortcut("-i")] public int IntOption { get; set; } diff --git a/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs b/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs index dd9de9b..9a655d0 100644 --- a/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs +++ b/CliFx.Benchmarks/Commands/SystemCommandLineCommand.cs @@ -14,7 +14,7 @@ namespace CliFx.Benchmarks.Commands { new Option(new[] {"--str", "-s"}) { - Argument = new Argument() + Argument = new Argument() }, new Option(new[] {"--int", "-i"}) { diff --git a/CliFx.Demo/CliFx.Demo.csproj b/CliFx.Demo/CliFx.Demo.csproj index 523cd1e..1566bf5 100644 --- a/CliFx.Demo/CliFx.Demo.csproj +++ b/CliFx.Demo/CliFx.Demo.csproj @@ -3,6 +3,7 @@ Exe netcoreapp3.0 + enable diff --git a/CliFx.Demo/Commands/BookAddCommand.cs b/CliFx.Demo/Commands/BookAddCommand.cs index 9bc8bcd..c94e355 100644 --- a/CliFx.Demo/Commands/BookAddCommand.cs +++ b/CliFx.Demo/Commands/BookAddCommand.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Demo.Internal; @@ -25,7 +24,7 @@ namespace CliFx.Demo.Commands public DateTimeOffset Published { get; set; } [CommandOption("isbn", 'n', Description = "Book ISBN.")] - public Isbn Isbn { get; set; } + public Isbn? Isbn { get; set; } public BookAddCommand(LibraryService libraryService) { diff --git a/CliFx.Demo/Commands/BookCommand.cs b/CliFx.Demo/Commands/BookCommand.cs index 406f695..2a4fb81 100644 --- a/CliFx.Demo/Commands/BookCommand.cs +++ b/CliFx.Demo/Commands/BookCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Demo.Internal; using CliFx.Demo.Services; diff --git a/CliFx.Demo/Commands/BookListCommand.cs b/CliFx.Demo/Commands/BookListCommand.cs index 2035bfd..e6077fe 100644 --- a/CliFx.Demo/Commands/BookListCommand.cs +++ b/CliFx.Demo/Commands/BookListCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Demo.Internal; using CliFx.Demo.Services; diff --git a/CliFx.Demo/Commands/BookRemoveCommand.cs b/CliFx.Demo/Commands/BookRemoveCommand.cs index 83047f2..ce7e771 100644 --- a/CliFx.Demo/Commands/BookRemoveCommand.cs +++ b/CliFx.Demo/Commands/BookRemoveCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Demo.Services; using CliFx.Exceptions; diff --git a/CliFx.Demo/Program.cs b/CliFx.Demo/Program.cs index 6a13bdd..b699782 100644 --- a/CliFx.Demo/Program.cs +++ b/CliFx.Demo/Program.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using CliFx.Demo.Commands; using CliFx.Demo.Services; using Microsoft.Extensions.DependencyInjection; @@ -7,7 +8,7 @@ namespace CliFx.Demo { public static class Program { - public static Task Main(string[] args) + private static IServiceProvider ConfigureServices() { // We use Microsoft.Extensions.DependencyInjection for injecting dependencies in commands var services = new ServiceCollection(); @@ -21,7 +22,12 @@ namespace CliFx.Demo services.AddTransient(); services.AddTransient(); - var serviceProvider = services.BuildServiceProvider(); + return services.BuildServiceProvider(); + } + + public static Task Main(string[] args) + { + var serviceProvider = ConfigureServices(); return new CliApplicationBuilder() .AddCommandsFromThisAssembly() diff --git a/CliFx.Tests/CliApplicationBuilderTests.cs b/CliFx.Tests/CliApplicationBuilderTests.cs index 171875c..ffb187f 100644 --- a/CliFx.Tests/CliApplicationBuilderTests.cs +++ b/CliFx.Tests/CliApplicationBuilderTests.cs @@ -21,8 +21,8 @@ namespace CliFx.Tests builder .AddCommand(typeof(HelloWorldDefaultCommand)) .AddCommandsFrom(typeof(HelloWorldDefaultCommand).Assembly) - .AddCommands(new[] { typeof(HelloWorldDefaultCommand) }) - .AddCommandsFrom(new[] { typeof(HelloWorldDefaultCommand).Assembly }) + .AddCommands(new[] {typeof(HelloWorldDefaultCommand)}) + .AddCommandsFrom(new[] {typeof(HelloWorldDefaultCommand).Assembly}) .AddCommandsFromThisAssembly() .AllowDebugMode() .AllowPreviewMode() @@ -31,7 +31,7 @@ namespace CliFx.Tests .UseVersionText("test") .UseDescription("test") .UseConsole(new VirtualConsole(TextWriter.Null)) - .UseCommandFactory(schema => (ICommand)Activator.CreateInstance(schema.Type)) + .UseCommandFactory(schema => (ICommand) Activator.CreateInstance(schema.Type!)!) .UseCommandOptionInputConverter(new CommandOptionInputConverter()) .UseEnvironmentVariablesProvider(new EnvironmentVariablesProviderStub()) .Build(); diff --git a/CliFx.Tests/CliApplicationTests.cs b/CliFx.Tests/CliApplicationTests.cs index 9547872..6d05e48 100644 --- a/CliFx.Tests/CliApplicationTests.cs +++ b/CliFx.Tests/CliApplicationTests.cs @@ -19,104 +19,104 @@ namespace CliFx.Tests private static IEnumerable GetTestCases_RunAsync() { yield return new TestCaseData( - new[] { typeof(HelloWorldDefaultCommand) }, + new[] {typeof(HelloWorldDefaultCommand)}, new string[0], "Hello world." ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "concat", "-i", "foo", "-i", "bar", "-s", " " }, + new[] {typeof(ConcatCommand)}, + new[] {"concat", "-i", "foo", "-i", "bar", "-s", " "}, "foo bar" ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "concat", "-i", "one", "two", "three", "-s", ", " }, + new[] {typeof(ConcatCommand)}, + new[] {"concat", "-i", "one", "two", "three", "-s", ", "}, "one, two, three" ); yield return new TestCaseData( - new[] { typeof(DivideCommand) }, - new[] { "div", "-D", "24", "-d", "8" }, + new[] {typeof(DivideCommand)}, + new[] {"div", "-D", "24", "-d", "8"}, "3" ); yield return new TestCaseData( - new[] { typeof(HelloWorldDefaultCommand) }, - new[] { "--version" }, + new[] {typeof(HelloWorldDefaultCommand)}, + new[] {"--version"}, TestVersionText ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "--version" }, + new[] {typeof(ConcatCommand)}, + new[] {"--version"}, TestVersionText ); yield return new TestCaseData( - new[] { typeof(HelloWorldDefaultCommand) }, - new[] { "-h" }, + new[] {typeof(HelloWorldDefaultCommand)}, + new[] {"-h"}, null ); yield return new TestCaseData( - new[] { typeof(HelloWorldDefaultCommand) }, - new[] { "--help" }, + new[] {typeof(HelloWorldDefaultCommand)}, + new[] {"--help"}, null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, + new[] {typeof(ConcatCommand)}, new string[0], null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "-h" }, + new[] {typeof(ConcatCommand)}, + new[] {"-h"}, null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "--help" }, + new[] {typeof(ConcatCommand)}, + new[] {"--help"}, null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "concat", "-h" }, + new[] {typeof(ConcatCommand)}, + new[] {"concat", "-h"}, null ); yield return new TestCaseData( - new[] { typeof(ExceptionCommand) }, - new[] { "exc", "-h" }, + new[] {typeof(ExceptionCommand)}, + new[] {"exc", "-h"}, null ); yield return new TestCaseData( - new[] { typeof(CommandExceptionCommand) }, - new[] { "exc", "-h" }, + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc", "-h"}, null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "[preview]" }, + new[] {typeof(ConcatCommand)}, + new[] {"[preview]"}, null ); yield return new TestCaseData( - new[] { typeof(ExceptionCommand) }, - new[] { "exc", "[preview]" }, + new[] {typeof(ExceptionCommand)}, + new[] {"exc", "[preview]"}, null ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "concat", "[preview]", "-o", "value" }, + new[] {typeof(ConcatCommand)}, + new[] {"concat", "[preview]", "-o", "value"}, null ); } @@ -130,38 +130,38 @@ namespace CliFx.Tests ); yield return new TestCaseData( - new[] { typeof(ConcatCommand) }, - new[] { "non-existing" }, + new[] {typeof(ConcatCommand)}, + new[] {"non-existing"}, null, null ); yield return new TestCaseData( - new[] { typeof(ExceptionCommand) }, - new[] { "exc" }, + new[] {typeof(ExceptionCommand)}, + new[] {"exc"}, null, null ); yield return new TestCaseData( - new[] { typeof(CommandExceptionCommand) }, - new[] { "exc" }, + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc"}, null, null ); yield return new TestCaseData( - new[] { typeof(CommandExceptionCommand) }, - new[] { "exc" }, + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc"}, null, null ); yield return new TestCaseData( - new[] { typeof(CommandExceptionCommand) }, - new[] { "exc", "-m", "foo bar" }, + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc", "-m", "foo bar"}, "foo bar", null ); yield return new TestCaseData( - new[] { typeof(CommandExceptionCommand) }, - new[] { "exc", "-m", "foo bar", "-c", "666" }, + new[] {typeof(CommandExceptionCommand)}, + new[] {"exc", "-m", "foo bar", "-c", "666"}, "foo bar", 666 ); } @@ -169,95 +169,92 @@ namespace CliFx.Tests [Test] [TestCaseSource(nameof(GetTestCases_RunAsync))] public async Task RunAsync_Test(IReadOnlyList commandTypes, IReadOnlyList commandLineArguments, - string expectedStdOut = null) + string? expectedStdOut = null) { // Arrange - using (var stdoutStream = new StringWriter()) - { - var console = new VirtualConsole(stdoutStream); - var environmentVariablesProvider = new EnvironmentVariablesProviderStub(); + await using var stdoutStream = new StringWriter(); - var application = new CliApplicationBuilder() - .AddCommands(commandTypes) - .UseVersionText(TestVersionText) - .UseConsole(console) - .UseEnvironmentVariablesProvider(environmentVariablesProvider) - .Build(); + var console = new VirtualConsole(stdoutStream); + var environmentVariablesProvider = new EnvironmentVariablesProviderStub(); - // Act - var exitCode = await application.RunAsync(commandLineArguments); - var stdOut = stdoutStream.ToString().Trim(); + var application = new CliApplicationBuilder() + .AddCommands(commandTypes) + .UseVersionText(TestVersionText) + .UseConsole(console) + .UseEnvironmentVariablesProvider(environmentVariablesProvider) + .Build(); - // Assert - exitCode.Should().Be(0); + // Act + var exitCode = await application.RunAsync(commandLineArguments); + var stdOut = stdoutStream.ToString().Trim(); - if (expectedStdOut != null) - stdOut.Should().Be(expectedStdOut); - else - stdOut.Should().NotBeNullOrWhiteSpace(); - } + // Assert + exitCode.Should().Be(0); + + if (expectedStdOut != null) + stdOut.Should().Be(expectedStdOut); + else + stdOut.Should().NotBeNullOrWhiteSpace(); } [Test] [TestCaseSource(nameof(GetTestCases_RunAsync_Negative))] public async Task RunAsync_Negative_Test(IReadOnlyList commandTypes, IReadOnlyList commandLineArguments, - string expectedStdErr = null, int? expectedExitCode = null) + string? expectedStdErr = null, int? expectedExitCode = null) { // Arrange - using (var stderrStream = new StringWriter()) - { - var console = new VirtualConsole(TextWriter.Null, stderrStream); - var environmentVariablesProvider = new EnvironmentVariablesProviderStub(); + await using var stderrStream = new StringWriter(); - var application = new CliApplicationBuilder() - .AddCommands(commandTypes) - .UseVersionText(TestVersionText) - .UseEnvironmentVariablesProvider(environmentVariablesProvider) - .UseConsole(console) - .Build(); + var console = new VirtualConsole(TextWriter.Null, stderrStream); + var environmentVariablesProvider = new EnvironmentVariablesProviderStub(); - // Act - var exitCode = await application.RunAsync(commandLineArguments); - var stderr = stderrStream.ToString().Trim(); + var application = new CliApplicationBuilder() + .AddCommands(commandTypes) + .UseVersionText(TestVersionText) + .UseEnvironmentVariablesProvider(environmentVariablesProvider) + .UseConsole(console) + .Build(); - // Assert - if (expectedExitCode != null) - exitCode.Should().Be(expectedExitCode); - else - exitCode.Should().NotBe(0); + // Act + var exitCode = await application.RunAsync(commandLineArguments); + var stderr = stderrStream.ToString().Trim(); - if (expectedStdErr != null) - stderr.Should().Be(expectedStdErr); - else - stderr.Should().NotBeNullOrWhiteSpace(); - } + // Assert + if (expectedExitCode != null) + exitCode.Should().Be(expectedExitCode); + else + exitCode.Should().NotBe(0); + + if (expectedStdErr != null) + stderr.Should().Be(expectedStdErr); + else + stderr.Should().NotBeNullOrWhiteSpace(); } [Test] public async Task RunAsync_Cancellation_Test() { // Arrange - using (var stdoutStream = new StringWriter()) - using (var cancellationTokenSource = new CancellationTokenSource()) - { - var console = new VirtualConsole(stdoutStream, cancellationTokenSource.Token); - - var application = new CliApplicationBuilder() - .AddCommand(typeof(CancellableCommand)) - .UseConsole(console) - .Build(); - var args = new[] { "cancel" }; + using var cancellationTokenSource = new CancellationTokenSource(); + await using var stdoutStream = new StringWriter(); - // Act - var runTask = application.RunAsync(args); - cancellationTokenSource.Cancel(); - var exitCode = await runTask.ConfigureAwait(false); - var stdOut = stdoutStream.ToString().Trim(); + var console = new VirtualConsole(stdoutStream, cancellationTokenSource.Token); - // Assert - exitCode.Should().Be(-2146233029); - stdOut.Should().Be("Printed"); - } + var application = new CliApplicationBuilder() + .AddCommand(typeof(CancellableCommand)) + .UseConsole(console) + .Build(); + var args = new[] {"cancel"}; + + // Act + var runTask = application.RunAsync(args); + cancellationTokenSource.Cancel(); + var exitCode = await runTask.ConfigureAwait(false); + var stdOut = stdoutStream.ToString().Trim(); + + // Assert + exitCode.Should().Be(-2146233029); + stdOut.Should().Be("Printed"); } } } \ No newline at end of file diff --git a/CliFx.Tests/CliFx.Tests.csproj b/CliFx.Tests/CliFx.Tests.csproj index 49a04c3..e9c498c 100644 --- a/CliFx.Tests/CliFx.Tests.csproj +++ b/CliFx.Tests/CliFx.Tests.csproj @@ -7,6 +7,7 @@ true opencover bin/$(Configuration)/Coverage.xml + enable diff --git a/CliFx.Tests/Services/DelegateCommandFactoryTests.cs b/CliFx.Tests/Services/DelegateCommandFactoryTests.cs index 4f4c08b..31183c5 100644 --- a/CliFx.Tests/Services/DelegateCommandFactoryTests.cs +++ b/CliFx.Tests/Services/DelegateCommandFactoryTests.cs @@ -18,7 +18,7 @@ namespace CliFx.Tests.Services private static IEnumerable GetTestCases_CreateCommand() { yield return new TestCaseData( - new Func(schema => (ICommand) Activator.CreateInstance(schema.Type)), + new Func(schema => (ICommand) Activator.CreateInstance(schema.Type!)!), GetCommandSchema(typeof(HelloWorldDefaultCommand)) ); } diff --git a/CliFx.Tests/Services/HelpTextRendererTests.cs b/CliFx.Tests/Services/HelpTextRendererTests.cs index 66f7486..ade3af9 100644 --- a/CliFx.Tests/Services/HelpTextRendererTests.cs +++ b/CliFx.Tests/Services/HelpTextRendererTests.cs @@ -93,17 +93,16 @@ namespace CliFx.Tests.Services IReadOnlyList expectedSubstrings) { // Arrange - using (var stdout = new StringWriter()) - { - var console = new VirtualConsole(stdout); - var renderer = new HelpTextRenderer(); + using var stdout = new StringWriter(); - // Act - renderer.RenderHelpText(console, source); + var console = new VirtualConsole(stdout); + var renderer = new HelpTextRenderer(); - // Assert - stdout.ToString().Should().ContainAll(expectedSubstrings); - } + // Act + renderer.RenderHelpText(console, source); + + // Assert + stdout.ToString().Should().ContainAll(expectedSubstrings); } } } \ No newline at end of file diff --git a/CliFx.Tests/Services/VirtualConsoleTests.cs b/CliFx.Tests/Services/VirtualConsoleTests.cs index 8b32e9f..be01d62 100644 --- a/CliFx.Tests/Services/VirtualConsoleTests.cs +++ b/CliFx.Tests/Services/VirtualConsoleTests.cs @@ -14,30 +14,29 @@ namespace CliFx.Tests.Services public void All_Smoke_Test() { // Arrange - using (var stdin = new StringReader("hello world")) - using (var stdout = new StringWriter()) - using (var stderr = new StringWriter()) - { - var console = new VirtualConsole(stdin, stdout, stderr); + using var stdin = new StringReader("hello world"); + using var stdout = new StringWriter(); + using var stderr = new StringWriter(); - // Act - console.ResetColor(); - console.ForegroundColor = ConsoleColor.DarkMagenta; - console.BackgroundColor = ConsoleColor.DarkMagenta; + var console = new VirtualConsole(stdin, stdout, stderr); - // Assert - console.Input.Should().BeSameAs(stdin); - console.Input.Should().NotBeSameAs(Console.In); - console.IsInputRedirected.Should().BeTrue(); - console.Output.Should().BeSameAs(stdout); - console.Output.Should().NotBeSameAs(Console.Out); - console.IsOutputRedirected.Should().BeTrue(); - console.Error.Should().BeSameAs(stderr); - console.Error.Should().NotBeSameAs(Console.Error); - console.IsErrorRedirected.Should().BeTrue(); - console.ForegroundColor.Should().NotBe(Console.ForegroundColor); - console.BackgroundColor.Should().NotBe(Console.BackgroundColor); - } + // Act + console.ResetColor(); + console.ForegroundColor = ConsoleColor.DarkMagenta; + console.BackgroundColor = ConsoleColor.DarkMagenta; + + // Assert + console.Input.Should().BeSameAs(stdin); + console.Input.Should().NotBeSameAs(Console.In); + console.IsInputRedirected.Should().BeTrue(); + console.Output.Should().BeSameAs(stdout); + console.Output.Should().NotBeSameAs(Console.Out); + console.IsOutputRedirected.Should().BeTrue(); + console.Error.Should().BeSameAs(stderr); + console.Error.Should().NotBeSameAs(Console.Error); + console.IsErrorRedirected.Should().BeTrue(); + console.ForegroundColor.Should().NotBe(Console.ForegroundColor); + console.BackgroundColor.Should().NotBe(Console.BackgroundColor); } } } \ No newline at end of file diff --git a/CliFx.Tests/TestCommands/CommandExceptionCommand.cs b/CliFx.Tests/TestCommands/CommandExceptionCommand.cs index 6e047ab..ffefaab 100644 --- a/CliFx.Tests/TestCommands/CommandExceptionCommand.cs +++ b/CliFx.Tests/TestCommands/CommandExceptionCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Exceptions; using CliFx.Services; @@ -13,7 +12,7 @@ namespace CliFx.Tests.TestCommands public int ExitCode { get; set; } = 1337; [CommandOption("msg", 'm')] - public string Message { get; set; } + public string? Message { get; set; } public Task ExecuteAsync(IConsole console) => throw new CommandException(Message, ExitCode); } diff --git a/CliFx.Tests/TestCommands/ConcatCommand.cs b/CliFx.Tests/TestCommands/ConcatCommand.cs index 48a65f9..e357230 100644 --- a/CliFx.Tests/TestCommands/ConcatCommand.cs +++ b/CliFx.Tests/TestCommands/ConcatCommand.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; diff --git a/CliFx.Tests/TestCommands/DivideCommand.cs b/CliFx.Tests/TestCommands/DivideCommand.cs index d29fe24..71dad4e 100644 --- a/CliFx.Tests/TestCommands/DivideCommand.cs +++ b/CliFx.Tests/TestCommands/DivideCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; diff --git a/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs b/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs index 3745658..61f313c 100644 --- a/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs +++ b/CliFx.Tests/TestCommands/DuplicateOptionNamesCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,10 +8,10 @@ namespace CliFx.Tests.TestCommands public class DuplicateOptionNamesCommand : ICommand { [CommandOption("fruits")] - public string Apples { get; set; } + public string? Apples { get; set; } [CommandOption("fruits")] - public string Oranges { get; set; } + public string? Oranges { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs b/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs index 41d2599..542d69f 100644 --- a/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs +++ b/CliFx.Tests/TestCommands/DuplicateOptionShortNamesCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,10 +8,10 @@ namespace CliFx.Tests.TestCommands public class DuplicateOptionShortNamesCommand : ICommand { [CommandOption('f')] - public string Apples { get; set; } + public string? Apples { get; set; } [CommandOption('f')] - public string Oranges { get; set; } + public string? Oranges { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/EnvironmentVariableCommand.cs b/CliFx.Tests/TestCommands/EnvironmentVariableCommand.cs index 33ab651..46eacd4 100644 --- a/CliFx.Tests/TestCommands/EnvironmentVariableCommand.cs +++ b/CliFx.Tests/TestCommands/EnvironmentVariableCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,7 +8,7 @@ namespace CliFx.Tests.TestCommands public class EnvironmentVariableCommand : ICommand { [CommandOption("opt", EnvironmentVariableName = "ENV_SINGLE_VALUE")] - public string Option { get; set; } + public string? Option { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/EnvironmentVariableWithMultipleValuesCommand.cs b/CliFx.Tests/TestCommands/EnvironmentVariableWithMultipleValuesCommand.cs index 653cc19..3eaf40d 100644 --- a/CliFx.Tests/TestCommands/EnvironmentVariableWithMultipleValuesCommand.cs +++ b/CliFx.Tests/TestCommands/EnvironmentVariableWithMultipleValuesCommand.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -10,7 +9,7 @@ namespace CliFx.Tests.TestCommands public class EnvironmentVariableWithMultipleValuesCommand : ICommand { [CommandOption("opt", EnvironmentVariableName = "ENV_MULTIPLE_VALUES")] - public IEnumerable Option { get; set; } + public IEnumerable? Option { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/EnvironmentVariableWithoutCollectionPropertyCommand.cs b/CliFx.Tests/TestCommands/EnvironmentVariableWithoutCollectionPropertyCommand.cs index 56f4b13..872ac91 100644 --- a/CliFx.Tests/TestCommands/EnvironmentVariableWithoutCollectionPropertyCommand.cs +++ b/CliFx.Tests/TestCommands/EnvironmentVariableWithoutCollectionPropertyCommand.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -10,7 +8,7 @@ namespace CliFx.Tests.TestCommands public class EnvironmentVariableWithoutCollectionPropertyCommand : ICommand { [CommandOption("opt", EnvironmentVariableName = "ENV_MULTIPLE_VALUES")] - public string Option { get; set; } + public string? Option { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/ExceptionCommand.cs b/CliFx.Tests/TestCommands/ExceptionCommand.cs index 4eb0417..9c7f478 100644 --- a/CliFx.Tests/TestCommands/ExceptionCommand.cs +++ b/CliFx.Tests/TestCommands/ExceptionCommand.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -10,7 +9,7 @@ namespace CliFx.Tests.TestCommands public class ExceptionCommand : ICommand { [CommandOption("msg", 'm')] - public string Message { get; set; } + public string? Message { get; set; } public Task ExecuteAsync(IConsole console) => throw new Exception(Message); } diff --git a/CliFx.Tests/TestCommands/HelloWorldDefaultCommand.cs b/CliFx.Tests/TestCommands/HelloWorldDefaultCommand.cs index b83685e..fd8eb9b 100644 --- a/CliFx.Tests/TestCommands/HelloWorldDefaultCommand.cs +++ b/CliFx.Tests/TestCommands/HelloWorldDefaultCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; diff --git a/CliFx.Tests/TestCommands/HelpDefaultCommand.cs b/CliFx.Tests/TestCommands/HelpDefaultCommand.cs index 54ac7fb..c130217 100644 --- a/CliFx.Tests/TestCommands/HelpDefaultCommand.cs +++ b/CliFx.Tests/TestCommands/HelpDefaultCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,10 +8,10 @@ namespace CliFx.Tests.TestCommands public class HelpDefaultCommand : ICommand { [CommandOption("option-a", 'a', Description = "OptionA description.")] - public string OptionA { get; set; } + public string? OptionA { get; set; } [CommandOption("option-b", 'b', Description = "OptionB description.")] - public string OptionB { get; set; } + public string? OptionB { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/HelpNamedCommand.cs b/CliFx.Tests/TestCommands/HelpNamedCommand.cs index 840be37..c6e3891 100644 --- a/CliFx.Tests/TestCommands/HelpNamedCommand.cs +++ b/CliFx.Tests/TestCommands/HelpNamedCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,10 +8,10 @@ namespace CliFx.Tests.TestCommands public class HelpNamedCommand : ICommand { [CommandOption("option-c", 'c', Description = "OptionC description.")] - public string OptionC { get; set; } + public string? OptionC { get; set; } [CommandOption("option-d", 'd', Description = "OptionD description.")] - public string OptionD { get; set; } + public string? OptionD { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/HelpSubCommand.cs b/CliFx.Tests/TestCommands/HelpSubCommand.cs index 602ab48..e284532 100644 --- a/CliFx.Tests/TestCommands/HelpSubCommand.cs +++ b/CliFx.Tests/TestCommands/HelpSubCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Attributes; using CliFx.Services; @@ -9,7 +8,7 @@ namespace CliFx.Tests.TestCommands public class HelpSubCommand : ICommand { [CommandOption("option-e", 'e', Description = "OptionE description.")] - public string OptionE { get; set; } + public string? OptionE { get; set; } public Task ExecuteAsync(IConsole console) => Task.CompletedTask; } diff --git a/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs b/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs index b00b7b8..6977532 100644 --- a/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs +++ b/CliFx.Tests/TestCommands/NonAnnotatedCommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Services; namespace CliFx.Tests.TestCommands diff --git a/CliFx.Tests/Utilities/ProgressTickerTests.cs b/CliFx.Tests/Utilities/ProgressTickerTests.cs index 74a4efb..0a3492b 100644 --- a/CliFx.Tests/Utilities/ProgressTickerTests.cs +++ b/CliFx.Tests/Utilities/ProgressTickerTests.cs @@ -17,41 +17,39 @@ namespace CliFx.Tests.Utilities // Arrange var formatProvider = CultureInfo.InvariantCulture; - using (var stdout = new StringWriter(formatProvider)) - { - var console = new VirtualConsole(TextReader.Null, false, stdout, false, TextWriter.Null, false); - var ticker = console.CreateProgressTicker(); + using var stdout = new StringWriter(formatProvider); - var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray(); - var progressStringValues = progressValues.Select(p => p.ToString("P2", formatProvider)).ToArray(); + var console = new VirtualConsole(TextReader.Null, false, stdout, false, TextWriter.Null, false); + var ticker = console.CreateProgressTicker(); - // Act - foreach (var progress in progressValues) - ticker.Report(progress); + var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray(); + var progressStringValues = progressValues.Select(p => p.ToString("P2", formatProvider)).ToArray(); - // Assert - stdout.ToString().Should().ContainAll(progressStringValues); - } + // Act + foreach (var progress in progressValues) + ticker.Report(progress); + + // Assert + stdout.ToString().Should().ContainAll(progressStringValues); } [Test] public void Report_Redirected_Test() { // Arrange - using (var stdout = new StringWriter()) - { - var console = new VirtualConsole(stdout); - var ticker = console.CreateProgressTicker(); + using var stdout = new StringWriter(); - var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray(); + var console = new VirtualConsole(stdout); + var ticker = console.CreateProgressTicker(); - // Act - foreach (var progress in progressValues) - ticker.Report(progress); + var progressValues = Enumerable.Range(0, 100).Select(p => p / 100.0).ToArray(); - // Assert - stdout.ToString().Should().BeEmpty(); - } + // Act + foreach (var progress in progressValues) + ticker.Report(progress); + + // Assert + stdout.ToString().Should().BeEmpty(); } } } \ No newline at end of file diff --git a/CliFx/Attributes/CommandAttribute.cs b/CliFx/Attributes/CommandAttribute.cs index 42fb155..aaa613f 100644 --- a/CliFx/Attributes/CommandAttribute.cs +++ b/CliFx/Attributes/CommandAttribute.cs @@ -10,27 +10,27 @@ namespace CliFx.Attributes { /// /// Command name. + /// This can be null if this is the default command. /// - public string Name { get; } + public string? Name { get; } /// /// Command description, which is used in help text. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Initializes an instance of . /// public CommandAttribute(string name) { - Name = name; // can be null + Name = name; } /// /// Initializes an instance of . /// public CommandAttribute() - : this(null) { } } diff --git a/CliFx/Attributes/CommandOptionAttribute.cs b/CliFx/Attributes/CommandOptionAttribute.cs index c0f34e8..a1b9ac3 100644 --- a/CliFx/Attributes/CommandOptionAttribute.cs +++ b/CliFx/Attributes/CommandOptionAttribute.cs @@ -10,11 +10,13 @@ namespace CliFx.Attributes { /// /// Option name. + /// Either or must be set. /// - public string Name { get; } + public string? Name { get; } /// /// Option short name. + /// Either or must be set. /// public char? ShortName { get; } @@ -26,27 +28,27 @@ namespace CliFx.Attributes /// /// Option description, which is used in help text. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Optional environment variable name that will be used as fallback value if no option value is specified. /// - public string EnvironmentVariableName { get; set; } + public string? EnvironmentVariableName { get; set; } /// /// Initializes an instance of . /// - public CommandOptionAttribute(string name, char? shortName) + private CommandOptionAttribute(string? name, char? shortName) { - Name = name; // can be null - ShortName = shortName; // can be null + Name = name; + ShortName = shortName; } /// /// Initializes an instance of . /// public CommandOptionAttribute(string name, char shortName) - : this(name, (char?)shortName) + : this(name, (char?) shortName) { } @@ -62,7 +64,7 @@ namespace CliFx.Attributes /// Initializes an instance of . /// public CommandOptionAttribute(char shortName) - : this(null, shortName) + : this(null, (char?) shortName) { } } diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index 91cf4b1..8b21f02 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -32,15 +32,15 @@ namespace CliFx IConsole console, ICommandInputParser commandInputParser, ICommandSchemaResolver commandSchemaResolver, ICommandFactory commandFactory, ICommandInitializer commandInitializer, IHelpTextRenderer helpTextRenderer) { - _metadata = metadata.GuardNotNull(nameof(metadata)); - _configuration = configuration.GuardNotNull(nameof(configuration)); + _metadata = metadata; + _configuration = configuration; - _console = console.GuardNotNull(nameof(console)); - _commandInputParser = commandInputParser.GuardNotNull(nameof(commandInputParser)); - _commandSchemaResolver = commandSchemaResolver.GuardNotNull(nameof(commandSchemaResolver)); - _commandFactory = commandFactory.GuardNotNull(nameof(commandFactory)); - _commandInitializer = commandInitializer.GuardNotNull(nameof(commandInitializer)); - _helpTextRenderer = helpTextRenderer.GuardNotNull(nameof(helpTextRenderer)); + _console = console; + _commandInputParser = commandInputParser; + _commandSchemaResolver = commandSchemaResolver; + _commandFactory = commandFactory; + _commandInitializer = commandInitializer; + _helpTextRenderer = helpTextRenderer; } private async Task HandleDebugDirectiveAsync(CommandInput commandInput) @@ -117,7 +117,7 @@ namespace CliFx } private int? HandleHelpOption(CommandInput commandInput, - IReadOnlyList availableCommandSchemas, CommandSchema targetCommandSchema) + IReadOnlyList availableCommandSchemas, CommandSchema? targetCommandSchema) { // Help should be rendered if it was requested, or when executing a command which isn't defined var shouldRenderHelp = commandInput.IsHelpOptionSpecified() || targetCommandSchema == null; @@ -180,8 +180,6 @@ namespace CliFx /// public async Task RunAsync(IReadOnlyList commandLineArguments) { - commandLineArguments.GuardNotNull(nameof(commandLineArguments)); - try { // Parse command input from arguments @@ -199,7 +197,7 @@ namespace CliFx HandlePreviewDirective(commandInput) ?? HandleVersionOption(commandInput) ?? HandleHelpOption(commandInput, availableCommandSchemas, targetCommandSchema) ?? - await HandleCommandExecutionAsync(commandInput, targetCommandSchema); + await HandleCommandExecutionAsync(commandInput, targetCommandSchema!); } catch (Exception ex) { @@ -207,7 +205,7 @@ namespace CliFx // Doing this also gets rid of the annoying Windows troubleshooting dialog that shows up on unhandled exceptions. // Prefer showing message without stack trace on exceptions coming from CliFx or on CommandException - if (!ex.Message.IsNullOrWhiteSpace() && (ex is CliFxException || ex is CommandException)) + if (!string.IsNullOrWhiteSpace(ex.Message) && (ex is CliFxException || ex is CommandException)) { _console.WithForegroundColor(ConsoleColor.Red, () => _console.Error.WriteLine(ex.Message)); } diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index e0be026..85bd103 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -19,20 +19,18 @@ namespace CliFx private bool _isDebugModeAllowed = true; private bool _isPreviewModeAllowed = true; - private string _title; - private string _executableName; - private string _versionText; - private string _description; - private IConsole _console; - private ICommandFactory _commandFactory; - private ICommandOptionInputConverter _commandOptionInputConverter; - private IEnvironmentVariablesProvider _environmentVariablesProvider; + private string? _title; + private string? _executableName; + private string? _versionText; + private string? _description; + private IConsole? _console; + private ICommandFactory? _commandFactory; + private ICommandOptionInputConverter? _commandOptionInputConverter; + private IEnvironmentVariablesProvider? _environmentVariablesProvider; /// public ICliApplicationBuilder AddCommand(Type commandType) { - commandType.GuardNotNull(nameof(commandType)); - _commandTypes.Add(commandType); return this; @@ -41,8 +39,6 @@ namespace CliFx /// public ICliApplicationBuilder AddCommandsFrom(Assembly commandAssembly) { - commandAssembly.GuardNotNull(nameof(commandAssembly)); - var commandTypes = commandAssembly.ExportedTypes .Where(t => t.Implements(typeof(ICommand))) .Where(t => t.IsDefined(typeof(CommandAttribute))) @@ -71,56 +67,56 @@ namespace CliFx /// public ICliApplicationBuilder UseTitle(string title) { - _title = title.GuardNotNull(nameof(title)); + _title = title; return this; } /// public ICliApplicationBuilder UseExecutableName(string executableName) { - _executableName = executableName.GuardNotNull(nameof(executableName)); + _executableName = executableName; return this; } /// public ICliApplicationBuilder UseVersionText(string versionText) { - _versionText = versionText.GuardNotNull(nameof(versionText)); + _versionText = versionText; return this; } /// - public ICliApplicationBuilder UseDescription(string description) + public ICliApplicationBuilder UseDescription(string? description) { - _description = description; // can be null + _description = description; return this; } /// public ICliApplicationBuilder UseConsole(IConsole console) { - _console = console.GuardNotNull(nameof(console)); + _console = console; return this; } /// public ICliApplicationBuilder UseCommandFactory(ICommandFactory factory) { - _commandFactory = factory.GuardNotNull(nameof(factory)); + _commandFactory = factory; return this; } /// public ICliApplicationBuilder UseCommandOptionInputConverter(ICommandOptionInputConverter converter) { - _commandOptionInputConverter = converter.GuardNotNull(nameof(converter)); + _commandOptionInputConverter = converter; return this; } /// public ICliApplicationBuilder UseEnvironmentVariablesProvider(IEnvironmentVariablesProvider environmentVariablesProvider) { - _environmentVariablesProvider = environmentVariablesProvider.GuardNotNull(nameof(environmentVariablesProvider)); + _environmentVariablesProvider = environmentVariablesProvider; return this; } @@ -128,13 +124,13 @@ namespace CliFx public ICliApplication Build() { // Use defaults for required parameters that were not configured - _title = _title ?? GetDefaultTitle() ?? "App"; - _executableName = _executableName ?? GetDefaultExecutableName() ?? "app"; - _versionText = _versionText ?? GetDefaultVersionText() ?? "v1.0"; - _console = _console ?? new SystemConsole(); - _commandFactory = _commandFactory ?? new CommandFactory(); - _commandOptionInputConverter = _commandOptionInputConverter ?? new CommandOptionInputConverter(); - _environmentVariablesProvider = _environmentVariablesProvider ?? new EnvironmentVariablesProvider(); + _title ??= GetDefaultTitle() ?? "App"; + _executableName ??= GetDefaultExecutableName() ?? "app"; + _versionText ??= GetDefaultVersionText() ?? "v1.0"; + _console ??= new SystemConsole(); + _commandFactory ??= new CommandFactory(); + _commandOptionInputConverter ??= new CommandOptionInputConverter(); + _environmentVariablesProvider ??= new EnvironmentVariablesProvider(); // Project parameters to expected types var metadata = new ApplicationMetadata(_title, _executableName, _versionText, _description); @@ -153,7 +149,7 @@ namespace CliFx // Entry assembly is null in tests private static Assembly EntryAssembly => LazyEntryAssembly.Value; - private static string GetDefaultTitle() => EntryAssembly?.GetName().Name; + private static string GetDefaultTitle() => EntryAssembly?.GetName().Name ?? ""; private static string GetDefaultExecutableName() { @@ -169,6 +165,6 @@ namespace CliFx return Path.GetFileNameWithoutExtension(entryAssemblyLocation); } - private static string GetDefaultVersionText() => EntryAssembly != null ? $"v{EntryAssembly.GetName().Version}" : null; + private static string GetDefaultVersionText() => EntryAssembly != null ? $"v{EntryAssembly.GetName().Version}" : ""; } } \ No newline at end of file diff --git a/CliFx/CliFx.csproj b/CliFx/CliFx.csproj index 8449eb4..371678e 100644 --- a/CliFx/CliFx.csproj +++ b/CliFx/CliFx.csproj @@ -1,7 +1,7 @@  - net45;netstandard2.0 + net45;netstandard2.0;netstandard2.1 0.0.7 Tyrrrz $(Company) @@ -18,11 +18,15 @@ True True snupkg + latest + enable - + + + diff --git a/CliFx/Exceptions/CliFxException.cs b/CliFx/Exceptions/CliFxException.cs index 5bbba9b..7e04e9d 100644 --- a/CliFx/Exceptions/CliFxException.cs +++ b/CliFx/Exceptions/CliFxException.cs @@ -10,7 +10,7 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - public CliFxException(string message) + public CliFxException(string? message) : base(message) { } @@ -18,7 +18,7 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - public CliFxException(string message, Exception innerException) + public CliFxException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/CliFx/Exceptions/CommandException.cs b/CliFx/Exceptions/CommandException.cs index 4b44994..af3d254 100644 --- a/CliFx/Exceptions/CommandException.cs +++ b/CliFx/Exceptions/CommandException.cs @@ -1,5 +1,4 @@ using System; -using CliFx.Internal; namespace CliFx.Exceptions { @@ -20,16 +19,16 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - public CommandException(string message, Exception innerException, int exitCode = DefaultExitCode) + public CommandException(string? message, Exception? innerException, int exitCode = DefaultExitCode) : base(message, innerException) { - ExitCode = exitCode.GuardNotZero(nameof(exitCode)); + ExitCode = exitCode != 0 ? exitCode : throw new ArgumentException("Exit code cannot be zero because that signifies success."); } /// /// Initializes an instance of . /// - public CommandException(string message, int exitCode = DefaultExitCode) + public CommandException(string? message, int exitCode = DefaultExitCode) : this(message, null, exitCode) { } diff --git a/CliFx/Extensions.cs b/CliFx/Extensions.cs index 19953f1..9b93860 100644 --- a/CliFx/Extensions.cs +++ b/CliFx/Extensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Reflection; -using CliFx.Internal; using CliFx.Models; using CliFx.Services; @@ -17,9 +16,6 @@ namespace CliFx /// public static ICliApplicationBuilder AddCommands(this ICliApplicationBuilder builder, IReadOnlyList commandTypes) { - builder.GuardNotNull(nameof(builder)); - commandTypes.GuardNotNull(nameof(commandTypes)); - foreach (var commandType in commandTypes) builder.AddCommand(commandType); @@ -31,9 +27,6 @@ namespace CliFx /// public static ICliApplicationBuilder AddCommandsFrom(this ICliApplicationBuilder builder, IReadOnlyList commandAssemblies) { - builder.GuardNotNull(nameof(builder)); - commandAssemblies.GuardNotNull(nameof(commandAssemblies)); - foreach (var commandAssembly in commandAssemblies) builder.AddCommandsFrom(commandAssembly); @@ -43,21 +36,13 @@ namespace CliFx /// /// Adds commands from calling assembly to the application. /// - public static ICliApplicationBuilder AddCommandsFromThisAssembly(this ICliApplicationBuilder builder) - { - builder.GuardNotNull(nameof(builder)); - return builder.AddCommandsFrom(Assembly.GetCallingAssembly()); - } + public static ICliApplicationBuilder AddCommandsFromThisAssembly(this ICliApplicationBuilder builder) => + builder.AddCommandsFrom(Assembly.GetCallingAssembly()); /// /// Configures application to use specified factory method for creating new instances of . /// - public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func factoryMethod) - { - builder.GuardNotNull(nameof(builder)); - factoryMethod.GuardNotNull(nameof(factoryMethod)); - - return builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod)); - } + public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func factoryMethod) => + builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod)); } } \ No newline at end of file diff --git a/CliFx/ICliApplicationBuilder.cs b/CliFx/ICliApplicationBuilder.cs index 374a96d..79d979d 100644 --- a/CliFx/ICliApplicationBuilder.cs +++ b/CliFx/ICliApplicationBuilder.cs @@ -47,7 +47,7 @@ namespace CliFx /// /// Sets application description, which appears in the help text. /// - ICliApplicationBuilder UseDescription(string description); + ICliApplicationBuilder UseDescription(string? description); /// /// Configures application to use specified implementation of . diff --git a/CliFx/ICommand.cs b/CliFx/ICommand.cs index 9d7f53a..9fb2c78 100644 --- a/CliFx/ICommand.cs +++ b/CliFx/ICommand.cs @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using CliFx.Services; namespace CliFx diff --git a/CliFx/Internal/Extensions.cs b/CliFx/Internal/Extensions.cs index 7018918..e16f015 100644 --- a/CliFx/Internal/Extensions.cs +++ b/CliFx/Internal/Extensions.cs @@ -8,8 +8,6 @@ namespace CliFx.Internal { internal static class Extensions { - public static bool IsNullOrWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s); - public static string Repeat(this char c, int count) => new string(c, count); public static string AsString(this char c) => c.Repeat(1); @@ -36,9 +34,9 @@ namespace CliFx.Internal public static bool Implements(this Type type, Type interfaceType) => type.GetInterfaces().Contains(interfaceType); - public static Type GetNullableUnderlyingType(this Type type) => Nullable.GetUnderlyingType(type); + public static Type? GetNullableUnderlyingType(this Type type) => Nullable.GetUnderlyingType(type); - public static Type GetEnumerableUnderlyingType(this Type type) + public static Type? GetEnumerableUnderlyingType(this Type type) { if (type.IsPrimitive) return null; @@ -65,5 +63,8 @@ namespace CliFx.Internal return array; } + + public static bool IsCollection(this Type type) => + type != typeof(string) && type.GetEnumerableUnderlyingType() != null; } } \ No newline at end of file diff --git a/CliFx/Internal/Guards.cs b/CliFx/Internal/Guards.cs deleted file mode 100644 index 4328445..0000000 --- a/CliFx/Internal/Guards.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace CliFx.Internal -{ - internal static class Guards - { - public static T GuardNotNull(this T o, string argName = null) where T : class => - o ?? throw new ArgumentNullException(argName); - - public static int GuardNotZero(this int i, string argName = null) => - i != 0 ? i : throw new ArgumentException("Cannot be zero.", argName); - } -} \ No newline at end of file diff --git a/CliFx/Models/ApplicationConfiguration.cs b/CliFx/Models/ApplicationConfiguration.cs index 0a56555..ec9f16a 100644 --- a/CliFx/Models/ApplicationConfiguration.cs +++ b/CliFx/Models/ApplicationConfiguration.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using CliFx.Internal; namespace CliFx.Models { @@ -30,7 +29,7 @@ namespace CliFx.Models public ApplicationConfiguration(IReadOnlyList commandTypes, bool isDebugModeAllowed, bool isPreviewModeAllowed) { - CommandTypes = commandTypes.GuardNotNull(nameof(commandTypes)); + CommandTypes = commandTypes; IsDebugModeAllowed = isDebugModeAllowed; IsPreviewModeAllowed = isPreviewModeAllowed; } diff --git a/CliFx/Models/ApplicationMetadata.cs b/CliFx/Models/ApplicationMetadata.cs index 5003e95..5c3f3b6 100644 --- a/CliFx/Models/ApplicationMetadata.cs +++ b/CliFx/Models/ApplicationMetadata.cs @@ -1,6 +1,4 @@ -using CliFx.Internal; - -namespace CliFx.Models +namespace CliFx.Models { /// /// Metadata associated with an application. @@ -25,17 +23,17 @@ namespace CliFx.Models /// /// Application description. /// - public string Description { get; } + public string? Description { get; } /// /// Initializes an instance of . /// - public ApplicationMetadata(string title, string executableName, string versionText, string description) + public ApplicationMetadata(string title, string executableName, string versionText, string? description) { - Title = title.GuardNotNull(nameof(title)); - ExecutableName = executableName.GuardNotNull(nameof(executableName)); - VersionText = versionText.GuardNotNull(nameof(versionText)); - Description = description; // can be null + Title = title; + ExecutableName = executableName; + VersionText = versionText; + Description = description; } } } \ No newline at end of file diff --git a/CliFx/Models/CommandInput.cs b/CliFx/Models/CommandInput.cs index b06bd1a..62c3003 100644 --- a/CliFx/Models/CommandInput.cs +++ b/CliFx/Models/CommandInput.cs @@ -13,7 +13,7 @@ namespace CliFx.Models /// Specified command name. /// Can be null if command was not specified. /// - public string CommandName { get; } + public string? CommandName { get; } /// /// Specified directives. @@ -33,18 +33,19 @@ namespace CliFx.Models /// /// Initializes an instance of . /// - public CommandInput(string commandName, IReadOnlyList directives, IReadOnlyList options, IReadOnlyDictionary environmentVariables) + public CommandInput(string? commandName, IReadOnlyList directives, IReadOnlyList options, + IReadOnlyDictionary environmentVariables) { - CommandName = commandName; // can be null - Directives = directives.GuardNotNull(nameof(directives)); - Options = options.GuardNotNull(nameof(options)); - EnvironmentVariables = environmentVariables.GuardNotNull(nameof(environmentVariables)); + CommandName = commandName; + Directives = directives; + Options = options; + EnvironmentVariables = environmentVariables; } /// /// Initializes an instance of . /// - public CommandInput(string commandName, IReadOnlyList directives, IReadOnlyList options) + public CommandInput(string? commandName, IReadOnlyList directives, IReadOnlyList options) : this(commandName, directives, options, EmptyEnvironmentVariables) { } @@ -52,7 +53,7 @@ namespace CliFx.Models /// /// Initializes an instance of . /// - public CommandInput(string commandName, IReadOnlyList options, IReadOnlyDictionary environmentVariables) + public CommandInput(string? commandName, IReadOnlyList options, IReadOnlyDictionary environmentVariables) : this(commandName, EmptyDirectives, options, environmentVariables) { } @@ -60,7 +61,7 @@ namespace CliFx.Models /// /// Initializes an instance of . /// - public CommandInput(string commandName, IReadOnlyList options) + public CommandInput(string? commandName, IReadOnlyList options) : this(commandName, EmptyDirectives, options) { } @@ -76,7 +77,7 @@ namespace CliFx.Models /// /// Initializes an instance of . /// - public CommandInput(string commandName) + public CommandInput(string? commandName) : this(commandName, EmptyOptions) { } @@ -86,7 +87,7 @@ namespace CliFx.Models { var buffer = new StringBuilder(); - if (!CommandName.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(CommandName)) buffer.Append(CommandName); foreach (var directive in Directives) diff --git a/CliFx/Models/CommandOptionInput.cs b/CliFx/Models/CommandOptionInput.cs index 819b260..06feb29 100644 --- a/CliFx/Models/CommandOptionInput.cs +++ b/CliFx/Models/CommandOptionInput.cs @@ -24,8 +24,8 @@ namespace CliFx.Models /// public CommandOptionInput(string alias, IReadOnlyList values) { - Alias = alias.GuardNotNull(nameof(alias)); - Values = values.GuardNotNull(nameof(values)); + Alias = alias; + Values = values; } /// diff --git a/CliFx/Models/CommandOptionSchema.cs b/CliFx/Models/CommandOptionSchema.cs index 7e47e33..3a66292 100644 --- a/CliFx/Models/CommandOptionSchema.cs +++ b/CliFx/Models/CommandOptionSchema.cs @@ -1,6 +1,5 @@ using System.Reflection; using System.Text; -using CliFx.Internal; namespace CliFx.Models { @@ -12,12 +11,12 @@ namespace CliFx.Models /// /// Underlying property. /// - public PropertyInfo Property { get; } + public PropertyInfo? Property { get; } /// /// Option name. /// - public string Name { get; } + public string? Name { get; } /// /// Option short name. @@ -32,24 +31,24 @@ namespace CliFx.Models /// /// Option description. /// - public string Description { get; } + public string? Description { get; } /// /// Optional environment variable name that will be used as fallback value if no option value is specified. /// - public string EnvironmentVariableName { get; } + public string? EnvironmentVariableName { get; } /// /// Initializes an instance of . /// - public CommandOptionSchema(PropertyInfo property, string name, char? shortName, bool isRequired, string description, string environmentVariableName) + public CommandOptionSchema(PropertyInfo? property, string? name, char? shortName, bool isRequired, string? description, string? environmentVariableName) { - Property = property; // can be null - Name = name; // can be null - ShortName = shortName; // can be null + Property = property; + Name = name; + ShortName = shortName; IsRequired = isRequired; - Description = description; // can be null - EnvironmentVariableName = environmentVariableName; //can be null + Description = description; + EnvironmentVariableName = environmentVariableName; } /// @@ -60,10 +59,10 @@ namespace CliFx.Models if (IsRequired) buffer.Append('*'); - if (!Name.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(Name)) buffer.Append(Name); - if (!Name.IsNullOrWhiteSpace() && ShortName != null) + if (!string.IsNullOrWhiteSpace(Name) && ShortName != null) buffer.Append('|'); if (ShortName != null) diff --git a/CliFx/Models/CommandSchema.cs b/CliFx/Models/CommandSchema.cs index 7cf4b51..2725732 100644 --- a/CliFx/Models/CommandSchema.cs +++ b/CliFx/Models/CommandSchema.cs @@ -13,17 +13,17 @@ namespace CliFx.Models /// /// Underlying type. /// - public Type Type { get; } + public Type? Type { get; } /// /// Command name. /// - public string Name { get; } + public string? Name { get; } /// /// Command description. /// - public string Description { get; } + public string? Description { get; } /// /// Command options. @@ -33,12 +33,12 @@ namespace CliFx.Models /// /// Initializes an instance of . /// - public CommandSchema(Type type, string name, string description, IReadOnlyList options) + public CommandSchema(Type? type, string? name, string? description, IReadOnlyList options) { - Type = type; // can be null - Name = name; // can be null - Description = description; // can be null - Options = options.GuardNotNull(nameof(options)); + Type = type; + Name = name; + Description = description; + Options = options; } /// @@ -46,7 +46,7 @@ namespace CliFx.Models { var buffer = new StringBuilder(); - if (!Name.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(Name)) buffer.Append(Name); foreach (var option in Options) diff --git a/CliFx/Models/Extensions.cs b/CliFx/Models/Extensions.cs index c9e0406..1ae5260 100644 --- a/CliFx/Models/Extensions.cs +++ b/CliFx/Models/Extensions.cs @@ -13,13 +13,11 @@ namespace CliFx.Models /// /// Finds a command that has specified name, or null if not found. /// - public static CommandSchema FindByName(this IReadOnlyList commandSchemas, string commandName) + public static CommandSchema? FindByName(this IReadOnlyList commandSchemas, string? commandName) { - commandSchemas.GuardNotNull(nameof(commandSchemas)); - // If looking for default command, don't compare names directly // ...because null and empty are both valid names for default command - if (commandName.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(commandName)) return commandSchemas.FirstOrDefault(c => c.IsDefault()); return commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); @@ -28,12 +26,10 @@ namespace CliFx.Models /// /// Finds parent command to the command that has specified name, or null if not found. /// - public static CommandSchema FindParent(this IReadOnlyList commandSchemas, string commandName) + public static CommandSchema? FindParent(this IReadOnlyList commandSchemas, string? commandName) { - commandSchemas.GuardNotNull(nameof(commandSchemas)); - // If command has no name, it's the default command so it doesn't have a parent - if (commandName.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(commandName)) return null; // Repeatedly cut off individual words from the name until we find a command with that name @@ -56,12 +52,9 @@ namespace CliFx.Models /// public static bool MatchesAlias(this CommandOptionSchema optionSchema, string alias) { - optionSchema.GuardNotNull(nameof(optionSchema)); - alias.GuardNotNull(nameof(alias)); - // Compare against name. Case is ignored. var matchesByName = - !optionSchema.Name.IsNullOrWhiteSpace() && + !string.IsNullOrWhiteSpace(optionSchema.Name) && string.Equals(optionSchema.Name, alias, StringComparison.OrdinalIgnoreCase); // Compare against short name. Case is NOT ignored. @@ -75,13 +68,8 @@ namespace CliFx.Models /// /// Finds an option input that matches the option schema specified, or null if not found. /// - public static CommandOptionInput FindByOptionSchema(this IReadOnlyList optionInputs, CommandOptionSchema optionSchema) - { - optionInputs.GuardNotNull(nameof(optionInputs)); - optionSchema.GuardNotNull(nameof(optionSchema)); - - return optionInputs.FirstOrDefault(o => optionSchema.MatchesAlias(o.Alias)); - } + public static CommandOptionInput? FindByOptionSchema(this IReadOnlyList optionInputs, CommandOptionSchema optionSchema) => + optionInputs.FirstOrDefault(o => optionSchema.MatchesAlias(o.Alias)); /// /// Gets valid aliases for the option. @@ -90,8 +78,8 @@ namespace CliFx.Models { var result = new List(2); - if (!optionSchema.Name.IsNullOrWhiteSpace()) - result.Add(optionSchema.Name); + if (!string.IsNullOrWhiteSpace(optionSchema.Name)) + result.Add(optionSchema.Name!); if (optionSchema.ShortName != null) result.Add(optionSchema.ShortName.Value.AsString()); @@ -102,37 +90,25 @@ namespace CliFx.Models /// /// Gets whether a command was specified in the input. /// - public static bool IsCommandSpecified(this CommandInput commandInput) - { - commandInput.GuardNotNull(nameof(commandInput)); - return !commandInput.CommandName.IsNullOrWhiteSpace(); - } + public static bool IsCommandSpecified(this CommandInput commandInput) => !string.IsNullOrWhiteSpace(commandInput.CommandName); /// /// Gets whether debug directive was specified in the input. /// - public static bool IsDebugDirectiveSpecified(this CommandInput commandInput) - { - commandInput.GuardNotNull(nameof(commandInput)); - return commandInput.Directives.Contains("debug", StringComparer.OrdinalIgnoreCase); - } + public static bool IsDebugDirectiveSpecified(this CommandInput commandInput) => + commandInput.Directives.Contains("debug", StringComparer.OrdinalIgnoreCase); /// /// Gets whether preview directive was specified in the input. /// - public static bool IsPreviewDirectiveSpecified(this CommandInput commandInput) - { - commandInput.GuardNotNull(nameof(commandInput)); - return commandInput.Directives.Contains("preview", StringComparer.OrdinalIgnoreCase); - } + public static bool IsPreviewDirectiveSpecified(this CommandInput commandInput) => + commandInput.Directives.Contains("preview", StringComparer.OrdinalIgnoreCase); /// /// Gets whether help option was specified in the input. /// public static bool IsHelpOptionSpecified(this CommandInput commandInput) { - commandInput.GuardNotNull(nameof(commandInput)); - var firstOption = commandInput.Options.FirstOrDefault(); return firstOption != null && CommandOptionSchema.HelpOption.MatchesAlias(firstOption.Alias); } @@ -142,8 +118,6 @@ namespace CliFx.Models /// public static bool IsVersionOptionSpecified(this CommandInput commandInput) { - commandInput.GuardNotNull(nameof(commandInput)); - var firstOption = commandInput.Options.FirstOrDefault(); return firstOption != null && CommandOptionSchema.VersionOption.MatchesAlias(firstOption.Alias); } @@ -151,10 +125,6 @@ namespace CliFx.Models /// /// Gets whether this command is the default command, i.e. without a name. /// - public static bool IsDefault(this CommandSchema commandSchema) - { - commandSchema.GuardNotNull(nameof(commandSchema)); - return commandSchema.Name.IsNullOrWhiteSpace(); - } + public static bool IsDefault(this CommandSchema commandSchema) => string.IsNullOrWhiteSpace(commandSchema.Name); } } \ No newline at end of file diff --git a/CliFx/Models/HelpTextSource.cs b/CliFx/Models/HelpTextSource.cs index f1968d0..556f522 100644 --- a/CliFx/Models/HelpTextSource.cs +++ b/CliFx/Models/HelpTextSource.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using CliFx.Internal; namespace CliFx.Models { @@ -30,9 +29,9 @@ namespace CliFx.Models IReadOnlyList availableCommandSchemas, CommandSchema targetCommandSchema) { - ApplicationMetadata = applicationMetadata.GuardNotNull(nameof(applicationMetadata)); - AvailableCommandSchemas = availableCommandSchemas.GuardNotNull(nameof(availableCommandSchemas)); - TargetCommandSchema = targetCommandSchema.GuardNotNull(nameof(targetCommandSchema)); + ApplicationMetadata = applicationMetadata; + AvailableCommandSchemas = availableCommandSchemas; + TargetCommandSchema = targetCommandSchema; } } } \ No newline at end of file diff --git a/CliFx/Services/CommandFactory.cs b/CliFx/Services/CommandFactory.cs index 261d9a4..9ddb184 100644 --- a/CliFx/Services/CommandFactory.cs +++ b/CliFx/Services/CommandFactory.cs @@ -1,5 +1,4 @@ using System; -using CliFx.Internal; using CliFx.Models; namespace CliFx.Services @@ -10,10 +9,6 @@ namespace CliFx.Services public class CommandFactory : ICommandFactory { /// - public ICommand CreateCommand(CommandSchema commandSchema) - { - commandSchema.GuardNotNull(nameof(commandSchema)); - return (ICommand) Activator.CreateInstance(commandSchema.Type); - } + public ICommand CreateCommand(CommandSchema commandSchema) => (ICommand) Activator.CreateInstance(commandSchema.Type); } } \ No newline at end of file diff --git a/CliFx/Services/CommandInitializer.cs b/CliFx/Services/CommandInitializer.cs index 046b071..e35d749 100644 --- a/CliFx/Services/CommandInitializer.cs +++ b/CliFx/Services/CommandInitializer.cs @@ -18,8 +18,8 @@ namespace CliFx.Services /// public CommandInitializer(ICommandOptionInputConverter commandOptionInputConverter, IEnvironmentVariablesParser environmentVariablesParser) { - _commandOptionInputConverter = commandOptionInputConverter.GuardNotNull(nameof(commandOptionInputConverter)); - _environmentVariablesParser = environmentVariablesParser.GuardNotNull(nameof(environmentVariablesParser)); + _commandOptionInputConverter = commandOptionInputConverter; + _environmentVariablesParser = environmentVariablesParser; } /// @@ -41,29 +41,29 @@ namespace CliFx.Services /// public void InitializeCommand(ICommand command, CommandSchema commandSchema, CommandInput commandInput) { - command.GuardNotNull(nameof(command)); - commandSchema.GuardNotNull(nameof(commandSchema)); - commandInput.GuardNotNull(nameof(commandInput)); - // Keep track of unset required options to report an error at a later stage var unsetRequiredOptions = commandSchema.Options.Where(o => o.IsRequired).ToList(); //Set command options foreach (var optionSchema in commandSchema.Options) { + // Ignore special options that are not backed by a property + if (optionSchema.Property == null) + continue; + //Find matching option input var optionInput = commandInput.Options.FindByOptionSchema(optionSchema); //If no option input is available fall back to environment variable values - if (optionInput == null && !optionSchema.EnvironmentVariableName.IsNullOrWhiteSpace()) + if (optionInput == null && !string.IsNullOrWhiteSpace(optionSchema.EnvironmentVariableName)) { - var fallbackEnvironmentVariableExists = commandInput.EnvironmentVariables.ContainsKey(optionSchema.EnvironmentVariableName); + var fallbackEnvironmentVariableExists = commandInput.EnvironmentVariables.ContainsKey(optionSchema.EnvironmentVariableName!); //If no environment variable is found or there is no valid value for this option skip it - if (!fallbackEnvironmentVariableExists || commandInput.EnvironmentVariables[optionSchema.EnvironmentVariableName].IsNullOrWhiteSpace()) + if (!fallbackEnvironmentVariableExists || string.IsNullOrWhiteSpace(commandInput.EnvironmentVariables[optionSchema.EnvironmentVariableName!])) continue; - optionInput = _environmentVariablesParser.GetCommandOptionInputFromEnvironmentVariable(commandInput.EnvironmentVariables[optionSchema.EnvironmentVariableName], optionSchema); + optionInput = _environmentVariablesParser.GetCommandOptionInputFromEnvironmentVariable(commandInput.EnvironmentVariables[optionSchema.EnvironmentVariableName!], optionSchema); } //No fallback available and no option input was specified, skip option diff --git a/CliFx/Services/CommandInputParser.cs b/CliFx/Services/CommandInputParser.cs index ac78cd4..1f3416f 100644 --- a/CliFx/Services/CommandInputParser.cs +++ b/CliFx/Services/CommandInputParser.cs @@ -19,8 +19,6 @@ namespace CliFx.Services /// public CommandInputParser(IEnvironmentVariablesProvider environmentVariablesProvider) { - environmentVariablesProvider.GuardNotNull(nameof(environmentVariablesProvider)); - _environmentVariablesProvider = environmentVariablesProvider; } @@ -35,8 +33,6 @@ namespace CliFx.Services /// public CommandInput ParseCommandInput(IReadOnlyList commandLineArguments) { - commandLineArguments.GuardNotNull(nameof(commandLineArguments)); - var commandNameBuilder = new StringBuilder(); var directives = new List(); var optionsDic = new Dictionary>(); @@ -71,7 +67,7 @@ namespace CliFx.Services } // Encountered directive or (part of) command name - else if (lastOptionAlias.IsNullOrWhiteSpace()) + else if (string.IsNullOrWhiteSpace(lastOptionAlias)) { if (commandLineArgument.StartsWith("[", StringComparison.OrdinalIgnoreCase) && commandLineArgument.EndsWith("]", StringComparison.OrdinalIgnoreCase)) @@ -89,7 +85,7 @@ namespace CliFx.Services } // Encountered option value - else if (!lastOptionAlias.IsNullOrWhiteSpace()) + else if (!string.IsNullOrWhiteSpace(lastOptionAlias)) { optionsDic[lastOptionAlias].Add(commandLineArgument); } diff --git a/CliFx/Services/CommandOptionInputConverter.cs b/CliFx/Services/CommandOptionInputConverter.cs index a9f9c89..c4006fc 100644 --- a/CliFx/Services/CommandOptionInputConverter.cs +++ b/CliFx/Services/CommandOptionInputConverter.cs @@ -20,7 +20,7 @@ namespace CliFx.Services /// public CommandOptionInputConverter(IFormatProvider formatProvider) { - _formatProvider = formatProvider.GuardNotNull(nameof(formatProvider)); + _formatProvider = formatProvider; } /// @@ -34,10 +34,8 @@ namespace CliFx.Services /// /// Converts a single string value to specified target type. /// - protected virtual object ConvertValue(string value, Type targetType) + protected virtual object? ConvertValue(string value, Type targetType) { - targetType.GuardNotNull(nameof(targetType)); - try { // String or object @@ -46,7 +44,7 @@ namespace CliFx.Services // Bool if (targetType == typeof(bool)) - return value.IsNullOrWhiteSpace() || bool.Parse(value); + return string.IsNullOrWhiteSpace(value) || bool.Parse(value); // Char if (targetType == typeof(char)) @@ -115,7 +113,7 @@ namespace CliFx.Services // Nullable var nullableUnderlyingType = targetType.GetNullableUnderlyingType(); if (nullableUnderlyingType != null) - return !value.IsNullOrWhiteSpace() ? ConvertValue(value, nullableUnderlyingType) : null; + return !string.IsNullOrWhiteSpace(value) ? ConvertValue(value, nullableUnderlyingType) : null; // Has a constructor that accepts a single string var stringConstructor = GetStringConstructor(targetType); @@ -143,11 +141,8 @@ namespace CliFx.Services } /// - public virtual object ConvertOptionInput(CommandOptionInput optionInput, Type targetType) + public virtual object? ConvertOptionInput(CommandOptionInput optionInput, Type targetType) { - optionInput.GuardNotNull(nameof(optionInput)); - targetType.GuardNotNull(nameof(targetType)); - // Get the underlying type of IEnumerable if it's implemented by the target type. // Ignore string type because it's IEnumerable but we don't treat it as such. var enumerableUnderlyingType = targetType != typeof(string) ? targetType.GetEnumerableUnderlyingType() : null; diff --git a/CliFx/Services/CommandSchemaResolver.cs b/CliFx/Services/CommandSchemaResolver.cs index 7820980..23ff8be 100644 --- a/CliFx/Services/CommandSchemaResolver.cs +++ b/CliFx/Services/CommandSchemaResolver.cs @@ -36,7 +36,7 @@ namespace CliFx.Services // Make sure there are no other options with the same name var existingOptionWithSameName = result - .Where(o => !o.Name.IsNullOrWhiteSpace()) + .Where(o => !string.IsNullOrWhiteSpace(o.Name)) .FirstOrDefault(o => string.Equals(o.Name, optionSchema.Name, StringComparison.OrdinalIgnoreCase)); if (existingOptionWithSameName != null) @@ -68,8 +68,6 @@ namespace CliFx.Services /// public IReadOnlyList GetCommandSchemas(IReadOnlyList commandTypes) { - commandTypes.GuardNotNull(nameof(commandTypes)); - // Make sure there's at least one command defined if (!commandTypes.Any()) { diff --git a/CliFx/Services/DelegateCommandFactory.cs b/CliFx/Services/DelegateCommandFactory.cs index e855b5d..5dcdb92 100644 --- a/CliFx/Services/DelegateCommandFactory.cs +++ b/CliFx/Services/DelegateCommandFactory.cs @@ -1,5 +1,4 @@ using System; -using CliFx.Internal; using CliFx.Models; namespace CliFx.Services @@ -16,14 +15,10 @@ namespace CliFx.Services /// public DelegateCommandFactory(Func factoryMethod) { - _factoryMethod = factoryMethod.GuardNotNull(nameof(factoryMethod)); + _factoryMethod = factoryMethod; } /// - public ICommand CreateCommand(CommandSchema commandSchema) - { - commandSchema.GuardNotNull(nameof(commandSchema)); - return _factoryMethod(commandSchema); - } + public ICommand CreateCommand(CommandSchema commandSchema) => _factoryMethod(commandSchema); } } \ No newline at end of file diff --git a/CliFx/Services/EnvironmentVariablesParser.cs b/CliFx/Services/EnvironmentVariablesParser.cs index 23aad29..c678d7a 100644 --- a/CliFx/Services/EnvironmentVariablesParser.cs +++ b/CliFx/Services/EnvironmentVariablesParser.cs @@ -11,17 +11,14 @@ namespace CliFx.Services /// public CommandOptionInput GetCommandOptionInputFromEnvironmentVariable(string environmentVariableValue, CommandOptionSchema targetOptionSchema) { - environmentVariableValue.GuardNotNull(nameof(environmentVariableValue)); - targetOptionSchema.GuardNotNull(nameof(targetOptionSchema)); - //If the option is not a collection do not split environment variable values - var optionIsCollection = targetOptionSchema.Property.PropertyType.IsCollection(); + var optionIsCollection = targetOptionSchema.Property != null && targetOptionSchema.Property.PropertyType.IsCollection(); if (!optionIsCollection) return new CommandOptionInput(targetOptionSchema.EnvironmentVariableName, environmentVariableValue); //If the option is a collection split the values using System separator, empty values are discarded var environmentVariableValues = environmentVariableValue.Split(Path.PathSeparator) - .Where(v => !v.IsNullOrWhiteSpace()) + .Where(v => !string.IsNullOrWhiteSpace(v)) .ToList(); return new CommandOptionInput(targetOptionSchema.EnvironmentVariableName, environmentVariableValues); diff --git a/CliFx/Services/Extensions.cs b/CliFx/Services/Extensions.cs index 4828dd5..7c39bd7 100644 --- a/CliFx/Services/Extensions.cs +++ b/CliFx/Services/Extensions.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using CliFx.Internal; namespace CliFx.Services { @@ -14,9 +12,6 @@ namespace CliFx.Services /// public static void WithForegroundColor(this IConsole console, ConsoleColor foregroundColor, Action action) { - console.GuardNotNull(nameof(console)); - action.GuardNotNull(nameof(action)); - var lastColor = console.ForegroundColor; console.ForegroundColor = foregroundColor; @@ -30,9 +25,6 @@ namespace CliFx.Services /// public static void WithBackgroundColor(this IConsole console, ConsoleColor backgroundColor, Action action) { - console.GuardNotNull(nameof(console)); - action.GuardNotNull(nameof(action)); - var lastColor = console.BackgroundColor; console.BackgroundColor = backgroundColor; @@ -44,32 +36,7 @@ namespace CliFx.Services /// /// Sets console foreground and background colors, executes specified action, and sets the colors back to the original values. /// - public static void WithColors(this IConsole console, ConsoleColor foregroundColor, ConsoleColor backgroundColor, Action action) - { - console.GuardNotNull(nameof(console)); - action.GuardNotNull(nameof(action)); - + public static void WithColors(this IConsole console, ConsoleColor foregroundColor, ConsoleColor backgroundColor, Action action) => console.WithForegroundColor(foregroundColor, () => console.WithBackgroundColor(backgroundColor, action)); - } - - /// - /// Gets wether a string representing an environment variable value is escaped (i.e.: surrounded by double quotation marks) - /// - public static bool IsEnvironmentVariableEscaped(this string environmentVariableValue) - { - environmentVariableValue.GuardNotNull(nameof(environmentVariableValue)); - - return environmentVariableValue.StartsWith("\"") && environmentVariableValue.EndsWith("\""); - } - - /// - /// Gets wether the supplied is a collection implementing - /// - public static bool IsCollection(this Type type) - { - type.GuardNotNull(nameof(type)); - - return type != typeof(string) && type.GetEnumerableUnderlyingType() != null; - } } } \ No newline at end of file diff --git a/CliFx/Services/HelpTextRenderer.cs b/CliFx/Services/HelpTextRenderer.cs index 9a521d1..4efd9b4 100644 --- a/CliFx/Services/HelpTextRenderer.cs +++ b/CliFx/Services/HelpTextRenderer.cs @@ -14,9 +14,6 @@ namespace CliFx.Services /// public void RenderHelpText(IConsole console, HelpTextSource source) { - console.GuardNotNull(nameof(console)); - source.GuardNotNull(nameof(source)); - // Track position var column = 0; var row = 0; @@ -105,7 +102,7 @@ namespace CliFx.Services RenderNewLine(); // Description - if (!source.ApplicationMetadata.Description.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(source.ApplicationMetadata.Description)) { Render(source.ApplicationMetadata.Description); RenderNewLine(); @@ -114,7 +111,7 @@ namespace CliFx.Services void RenderDescription() { - if (source.TargetCommandSchema.Description.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(source.TargetCommandSchema.Description)) return; // Margin @@ -142,7 +139,7 @@ namespace CliFx.Services Render(source.ApplicationMetadata.ExecutableName); // Command name - if (!source.TargetCommandSchema.IsDefault()) + if (!string.IsNullOrWhiteSpace(source.TargetCommandSchema.Name)) { Render(" "); RenderWithColor(source.TargetCommandSchema.Name, ConsoleColor.Cyan); @@ -195,19 +192,19 @@ namespace CliFx.Services } // Delimiter - if (!optionSchema.Name.IsNullOrWhiteSpace() && optionSchema.ShortName != null) + if (!string.IsNullOrWhiteSpace(optionSchema.Name) && optionSchema.ShortName != null) { Render("|"); } // Name - if (!optionSchema.Name.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(optionSchema.Name)) { RenderWithColor($"--{optionSchema.Name}", ConsoleColor.White); } // Description - if (!optionSchema.Description.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(optionSchema.Description)) { RenderColumnIndent(); Render(optionSchema.Description); @@ -231,14 +228,14 @@ namespace CliFx.Services // Child commands foreach (var childCommandSchema in childCommandSchemas) { - var relativeCommandName = GetRelativeCommandName(childCommandSchema, source.TargetCommandSchema); + var relativeCommandName = GetRelativeCommandName(childCommandSchema, source.TargetCommandSchema)!; // Name RenderIndent(); RenderWithColor(relativeCommandName, ConsoleColor.Cyan); // Description - if (!childCommandSchema.Description.IsNullOrWhiteSpace()) + if (!string.IsNullOrWhiteSpace(childCommandSchema.Description)) { RenderColumnIndent(); Render(childCommandSchema.Description); @@ -254,7 +251,7 @@ namespace CliFx.Services Render("You can run `"); Render(source.ApplicationMetadata.ExecutableName); - if (!source.TargetCommandSchema.IsDefault()) + if (!string.IsNullOrWhiteSpace(source.TargetCommandSchema.Name)) { Render(" "); RenderWithColor(source.TargetCommandSchema.Name, ConsoleColor.Cyan); @@ -285,8 +282,8 @@ namespace CliFx.Services public partial class HelpTextRenderer { - private static string GetRelativeCommandName(CommandSchema commandSchema, CommandSchema parentCommandSchema) => - parentCommandSchema.Name.IsNullOrWhiteSpace() + private static string? GetRelativeCommandName(CommandSchema commandSchema, CommandSchema parentCommandSchema) => + string.IsNullOrWhiteSpace(parentCommandSchema.Name) || string.IsNullOrWhiteSpace(commandSchema.Name) ? commandSchema.Name : commandSchema.Name.Substring(parentCommandSchema.Name.Length + 1); } diff --git a/CliFx/Services/ICommandOptionInputConverter.cs b/CliFx/Services/ICommandOptionInputConverter.cs index 42cdcfe..8e51b09 100644 --- a/CliFx/Services/ICommandOptionInputConverter.cs +++ b/CliFx/Services/ICommandOptionInputConverter.cs @@ -11,6 +11,6 @@ namespace CliFx.Services /// /// Converts an option to specified target type. /// - object ConvertOptionInput(CommandOptionInput optionInput, Type targetType); + object? ConvertOptionInput(CommandOptionInput optionInput, Type targetType); } } \ No newline at end of file diff --git a/CliFx/Services/SystemConsole.cs b/CliFx/Services/SystemConsole.cs index 47456e5..865edad 100644 --- a/CliFx/Services/SystemConsole.cs +++ b/CliFx/Services/SystemConsole.cs @@ -9,7 +9,7 @@ namespace CliFx.Services /// public class SystemConsole : IConsole { - private CancellationTokenSource _cancellationTokenSource; + private CancellationTokenSource? _cancellationTokenSource; /// public TextReader Input => Console.In; diff --git a/CliFx/Services/VirtualConsole.cs b/CliFx/Services/VirtualConsole.cs index 73ce481..05382fb 100644 --- a/CliFx/Services/VirtualConsole.cs +++ b/CliFx/Services/VirtualConsole.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Threading; -using CliFx.Internal; namespace CliFx.Services { @@ -46,11 +45,11 @@ namespace CliFx.Services TextWriter error, bool isErrorRedirected, CancellationToken cancellationToken = default) { - Input = input.GuardNotNull(nameof(input)); + Input = input; IsInputRedirected = isInputRedirected; - Output = output.GuardNotNull(nameof(output)); + Output = output; IsOutputRedirected = isOutputRedirected; - Error = error.GuardNotNull(nameof(error)); + Error = error; IsErrorRedirected = isErrorRedirected; _cancellationToken = cancellationToken; }