From 5a08b8c19b3f92131e79f7d96c5f9136bf3d8e0a Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Wed, 14 Aug 2019 13:49:14 +0300 Subject: [PATCH] Add guards --- CliFx/Attributes/CommandAttribute.cs | 2 +- CliFx/Attributes/CommandOptionAttribute.cs | 4 +-- CliFx/CliApplication.cs | 18 ++++++------ CliFx/CliApplicationBuilder.cs | 17 +++++++---- CliFx/Exceptions/CommandErrorException.cs | 3 +- CliFx/Extensions.cs | 23 ++++++++++++--- CliFx/ICliApplicationBuilder.cs | 2 +- CliFx/Internal/Guards.cs | 13 +++++++++ CliFx/Models/ApplicationMetadata.cs | 10 ++++--- CliFx/Models/CommandInput.cs | 5 ++-- CliFx/Models/CommandOptionInput.cs | 5 ++-- CliFx/Models/CommandOptionSchema.cs | 10 +++---- CliFx/Models/CommandSchema.cs | 8 +++--- CliFx/Models/Extensions.cs | 28 ++++++++++++++++--- CliFx/Models/HelpTextSource.cs | 7 +++-- CliFx/Services/CommandFactory.cs | 7 ++++- CliFx/Services/CommandHelpTextRenderer.cs | 3 ++ CliFx/Services/CommandInitializer.cs | 6 +++- CliFx/Services/CommandInputParser.cs | 2 ++ CliFx/Services/CommandOptionInputConverter.cs | 5 +++- CliFx/Services/CommandSchemaResolver.cs | 3 +- CliFx/Services/DelegateCommandFactory.cs | 9 ++++-- CliFx/Services/Extensions.cs | 22 +++++++++++++-- CliFx/Services/TestConsole.cs | 7 +++-- 24 files changed, 160 insertions(+), 59 deletions(-) create mode 100644 CliFx/Internal/Guards.cs diff --git a/CliFx/Attributes/CommandAttribute.cs b/CliFx/Attributes/CommandAttribute.cs index 7cc3cd5..42fb155 100644 --- a/CliFx/Attributes/CommandAttribute.cs +++ b/CliFx/Attributes/CommandAttribute.cs @@ -23,7 +23,7 @@ namespace CliFx.Attributes /// public CommandAttribute(string name) { - Name = name; + Name = name; // can be null } /// diff --git a/CliFx/Attributes/CommandOptionAttribute.cs b/CliFx/Attributes/CommandOptionAttribute.cs index 8860d81..85019af 100644 --- a/CliFx/Attributes/CommandOptionAttribute.cs +++ b/CliFx/Attributes/CommandOptionAttribute.cs @@ -38,8 +38,8 @@ namespace CliFx.Attributes /// public CommandOptionAttribute(string name, char? shortName) { - Name = name; - ShortName = shortName; + Name = name; // can be null + ShortName = shortName; // can be null } /// diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index a262cc5..a81b6c6 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, ICommandHelpTextRenderer commandHelpTextRenderer) { - _applicationMetadata = applicationMetadata; - _commandTypes = commandTypes; + _applicationMetadata = applicationMetadata.GuardNotNull(nameof(applicationMetadata)); + _commandTypes = commandTypes.GuardNotNull(nameof(commandTypes)); - _console = console; - _commandInputParser = commandInputParser; - _commandSchemaResolver = commandSchemaResolver; - _commandFactory = commandFactory; - _commandInitializer = commandInitializer; - _commandHelpTextRenderer = commandHelpTextRenderer; + _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)); + _commandHelpTextRenderer = commandHelpTextRenderer.GuardNotNull(nameof(commandHelpTextRenderer)); } private IReadOnlyList GetAvailableCommandSchemasValidationErrors(IReadOnlyList availableCommandSchemas) @@ -107,6 +107,8 @@ namespace CliFx /// public async Task RunAsync(IReadOnlyList commandLineArguments) { + commandLineArguments.GuardNotNull(nameof(commandLineArguments)); + try { var commandInput = _commandInputParser.ParseInput(commandLineArguments); diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index 2fcb1aa..e73874c 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -25,13 +25,18 @@ namespace CliFx /// public ICliApplicationBuilder WithCommand(Type commandType) { + commandType.GuardNotNull(nameof(commandType)); + _commandTypes.Add(commandType); + return this; } /// public ICliApplicationBuilder WithCommandsFrom(Assembly commandAssembly) { + commandAssembly.GuardNotNull(nameof(commandAssembly)); + var commandTypes = commandAssembly.ExportedTypes.Where(t => t.Implements(typeof(ICommand))); foreach (var commandType in commandTypes) @@ -43,35 +48,35 @@ namespace CliFx /// public ICliApplicationBuilder UseTitle(string title) { - _title = title; + _title = title.GuardNotNull(nameof(title)); return this; } /// public ICliApplicationBuilder UseExecutableName(string executableName) { - _executableName = executableName; + _executableName = executableName.GuardNotNull(nameof(executableName)); return this; } /// - public ICliApplicationBuilder UseVersionText(string version) + public ICliApplicationBuilder UseVersionText(string versionText) { - _versionText = version; + _versionText = versionText.GuardNotNull(nameof(versionText)); return this; } /// public ICliApplicationBuilder UseConsole(IConsole console) { - _console = console; + _console = console.GuardNotNull(nameof(console)); return this; } /// public ICliApplicationBuilder UseCommandFactory(ICommandFactory factory) { - _commandFactory = factory; + _commandFactory = factory.GuardNotNull(nameof(factory)); return this; } diff --git a/CliFx/Exceptions/CommandErrorException.cs b/CliFx/Exceptions/CommandErrorException.cs index 830fcc9..41eacd9 100644 --- a/CliFx/Exceptions/CommandErrorException.cs +++ b/CliFx/Exceptions/CommandErrorException.cs @@ -1,4 +1,5 @@ using System; +using CliFx.Internal; namespace CliFx.Exceptions { @@ -19,7 +20,7 @@ namespace CliFx.Exceptions public CommandErrorException(int exitCode, string message, Exception innerException) : base(message, innerException) { - ExitCode = exitCode; + ExitCode = exitCode.GuardNotZero(nameof(exitCode)); } /// diff --git a/CliFx/Extensions.cs b/CliFx/Extensions.cs index c9a1a5a..15dd50d 100644 --- a/CliFx/Extensions.cs +++ b/CliFx/Extensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using CliFx.Internal; using CliFx.Services; namespace CliFx @@ -15,6 +16,9 @@ namespace CliFx /// public static ICliApplicationBuilder WithCommands(this ICliApplicationBuilder builder, IReadOnlyList commandTypes) { + builder.GuardNotNull(nameof(builder)); + commandTypes.GuardNotNull(nameof(commandTypes)); + foreach (var commandType in commandTypes) builder.WithCommand(commandType); @@ -26,6 +30,9 @@ namespace CliFx /// public static ICliApplicationBuilder WithCommandsFrom(this ICliApplicationBuilder builder, IReadOnlyList commandAssemblies) { + builder.GuardNotNull(nameof(builder)); + commandAssemblies.GuardNotNull(nameof(commandAssemblies)); + foreach (var commandAssembly in commandAssemblies) builder.WithCommandsFrom(commandAssembly); @@ -35,13 +42,21 @@ namespace CliFx /// /// Adds commands from calling assembly to the application. /// - public static ICliApplicationBuilder WithCommandsFromThisAssembly(this ICliApplicationBuilder builder) => - builder.WithCommandsFrom(Assembly.GetCallingAssembly()); + public static ICliApplicationBuilder WithCommandsFromThisAssembly(this ICliApplicationBuilder builder) + { + builder.GuardNotNull(nameof(builder)); + return builder.WithCommandsFrom(Assembly.GetCallingAssembly()); + } /// /// Configures application to use specified factory method for creating new instances of . /// - public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func factoryMethod) => - builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod)); + public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func factoryMethod) + { + builder.GuardNotNull(nameof(builder)); + factoryMethod.GuardNotNull(nameof(factoryMethod)); + + return builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod)); + } } } \ No newline at end of file diff --git a/CliFx/ICliApplicationBuilder.cs b/CliFx/ICliApplicationBuilder.cs index 5842ce3..5bdbac5 100644 --- a/CliFx/ICliApplicationBuilder.cs +++ b/CliFx/ICliApplicationBuilder.cs @@ -32,7 +32,7 @@ namespace CliFx /// /// Sets application version text, which appears in the help text and when the user requests version information. /// - ICliApplicationBuilder UseVersionText(string version); + ICliApplicationBuilder UseVersionText(string versionText); /// /// Configures application to use specified implementation of . diff --git a/CliFx/Internal/Guards.cs b/CliFx/Internal/Guards.cs new file mode 100644 index 0000000..4328445 --- /dev/null +++ b/CliFx/Internal/Guards.cs @@ -0,0 +1,13 @@ +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/ApplicationMetadata.cs b/CliFx/Models/ApplicationMetadata.cs index 8cafd7d..e7bd062 100644 --- a/CliFx/Models/ApplicationMetadata.cs +++ b/CliFx/Models/ApplicationMetadata.cs @@ -1,4 +1,6 @@ -namespace CliFx.Models +using CliFx.Internal; + +namespace CliFx.Models { /// /// Metadata associated with an application. @@ -25,9 +27,9 @@ /// public ApplicationMetadata(string title, string executableName, string versionText) { - Title = title; - ExecutableName = executableName; - VersionText = versionText; + Title = title.GuardNotNull(nameof(title)); + ExecutableName = executableName.GuardNotNull(nameof(executableName)); + VersionText = versionText.GuardNotNull(nameof(versionText)); } } } \ No newline at end of file diff --git a/CliFx/Models/CommandInput.cs b/CliFx/Models/CommandInput.cs index b637a7b..165d23f 100644 --- a/CliFx/Models/CommandInput.cs +++ b/CliFx/Models/CommandInput.cs @@ -11,6 +11,7 @@ namespace CliFx.Models { /// /// Specified command name. + /// Can be null if command was not specified. /// public string CommandName { get; } @@ -24,8 +25,8 @@ namespace CliFx.Models /// public CommandInput(string commandName, IReadOnlyList options) { - CommandName = commandName; - Options = options; + CommandName = commandName; // can be null + Options = options.GuardNotNull(nameof(options)); } /// diff --git a/CliFx/Models/CommandOptionInput.cs b/CliFx/Models/CommandOptionInput.cs index ded3eb3..588d373 100644 --- a/CliFx/Models/CommandOptionInput.cs +++ b/CliFx/Models/CommandOptionInput.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using CliFx.Internal; namespace CliFx.Models { @@ -23,8 +24,8 @@ namespace CliFx.Models /// public CommandOptionInput(string alias, IReadOnlyList values) { - Alias = alias; - Values = values; + Alias = alias.GuardNotNull(nameof(alias)); + Values = values.GuardNotNull(nameof(values)); } /// diff --git a/CliFx/Models/CommandOptionSchema.cs b/CliFx/Models/CommandOptionSchema.cs index 2fedebd..764be28 100644 --- a/CliFx/Models/CommandOptionSchema.cs +++ b/CliFx/Models/CommandOptionSchema.cs @@ -45,12 +45,12 @@ namespace CliFx.Models public CommandOptionSchema(PropertyInfo property, string name, char? shortName, string groupName, bool isRequired, string description) { - Property = property; - Name = name; - ShortName = shortName; + Property = property; // can be null + Name = name; // can be null + ShortName = shortName; // can be null IsRequired = isRequired; - GroupName = groupName; - Description = description; + GroupName = groupName; // can be null + Description = description; // can be null } /// diff --git a/CliFx/Models/CommandSchema.cs b/CliFx/Models/CommandSchema.cs index c59d073..a2578a6 100644 --- a/CliFx/Models/CommandSchema.cs +++ b/CliFx/Models/CommandSchema.cs @@ -35,10 +35,10 @@ namespace CliFx.Models /// public CommandSchema(Type type, string name, string description, IReadOnlyList options) { - Type = type; - Name = name; - Description = description; - Options = options; + Type = type; // can be null + Name = name; // can be null + Description = description; // can be null + Options = options.GuardNotNull(nameof(options)); } /// diff --git a/CliFx/Models/Extensions.cs b/CliFx/Models/Extensions.cs index a3d6e52..94fa1e6 100644 --- a/CliFx/Models/Extensions.cs +++ b/CliFx/Models/Extensions.cs @@ -13,13 +13,19 @@ namespace CliFx.Models /// /// Gets whether a command was specified in the input. /// - public static bool IsCommandSpecified(this CommandInput commandInput) => !commandInput.CommandName.IsNullOrWhiteSpace(); + public static bool IsCommandSpecified(this CommandInput commandInput) + { + commandInput.GuardNotNull(nameof(commandInput)); + return !commandInput.CommandName.IsNullOrWhiteSpace(); + } /// /// Gets whether help was requested in the input. /// public static bool IsHelpRequested(this CommandInput commandInput) { + commandInput.GuardNotNull(nameof(commandInput)); + var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias; return string.Equals(firstOptionAlias, "help", StringComparison.OrdinalIgnoreCase) || @@ -32,6 +38,8 @@ namespace CliFx.Models /// public static bool IsVersionRequested(this CommandInput commandInput) { + commandInput.GuardNotNull(nameof(commandInput)); + var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias; return string.Equals(firstOptionAlias, "version", StringComparison.OrdinalIgnoreCase); @@ -40,19 +48,28 @@ namespace CliFx.Models /// /// Gets whether this command is the default command, i.e. without a name. /// - public static bool IsDefault(this CommandSchema commandSchema) => commandSchema.Name.IsNullOrWhiteSpace(); + public static bool IsDefault(this CommandSchema commandSchema) + { + commandSchema.GuardNotNull(nameof(commandSchema)); + return commandSchema.Name.IsNullOrWhiteSpace(); + } /// /// Finds a command that has specified name, or null if not found. /// - public static CommandSchema FindByName(this IReadOnlyList commandSchemas, string commandName) => - commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); + public static CommandSchema FindByName(this IReadOnlyList commandSchemas, string commandName) + { + commandSchemas.GuardNotNull(nameof(commandSchemas)); + return commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); + } /// /// Finds parent command to the command that has specified name, or null if not found. /// 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()) return null; @@ -77,6 +94,9 @@ namespace CliFx.Models /// public static CommandOptionSchema FindByAlias(this IReadOnlyList optionSchemas, string alias) { + optionSchemas.GuardNotNull(nameof(optionSchemas)); + alias.GuardNotNull(nameof(alias)); + foreach (var optionSchema in optionSchemas) { // Compare against name. Case is ignored. diff --git a/CliFx/Models/HelpTextSource.cs b/CliFx/Models/HelpTextSource.cs index 556f522..f1968d0 100644 --- a/CliFx/Models/HelpTextSource.cs +++ b/CliFx/Models/HelpTextSource.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using CliFx.Internal; namespace CliFx.Models { @@ -29,9 +30,9 @@ namespace CliFx.Models IReadOnlyList availableCommandSchemas, CommandSchema targetCommandSchema) { - ApplicationMetadata = applicationMetadata; - AvailableCommandSchemas = availableCommandSchemas; - TargetCommandSchema = targetCommandSchema; + ApplicationMetadata = applicationMetadata.GuardNotNull(nameof(applicationMetadata)); + AvailableCommandSchemas = availableCommandSchemas.GuardNotNull(nameof(availableCommandSchemas)); + TargetCommandSchema = targetCommandSchema.GuardNotNull(nameof(targetCommandSchema)); } } } \ No newline at end of file diff --git a/CliFx/Services/CommandFactory.cs b/CliFx/Services/CommandFactory.cs index 98b36fb..079b35e 100644 --- a/CliFx/Services/CommandFactory.cs +++ b/CliFx/Services/CommandFactory.cs @@ -1,4 +1,5 @@ using System; +using CliFx.Internal; namespace CliFx.Services { @@ -8,6 +9,10 @@ namespace CliFx.Services public class CommandFactory : ICommandFactory { /// - public ICommand CreateCommand(Type commandType) => (ICommand) Activator.CreateInstance(commandType); + public ICommand CreateCommand(Type commandType) + { + commandType.GuardNotNull(nameof(commandType)); + return (ICommand) Activator.CreateInstance(commandType); + } } } \ No newline at end of file diff --git a/CliFx/Services/CommandHelpTextRenderer.cs b/CliFx/Services/CommandHelpTextRenderer.cs index 966b278..143e97e 100644 --- a/CliFx/Services/CommandHelpTextRenderer.cs +++ b/CliFx/Services/CommandHelpTextRenderer.cs @@ -14,6 +14,9 @@ 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; diff --git a/CliFx/Services/CommandInitializer.cs b/CliFx/Services/CommandInitializer.cs index 8f82c01..67e7139 100644 --- a/CliFx/Services/CommandInitializer.cs +++ b/CliFx/Services/CommandInitializer.cs @@ -19,7 +19,7 @@ namespace CliFx.Services /// public CommandInitializer(ICommandOptionInputConverter commandOptionInputConverter) { - _commandOptionInputConverter = commandOptionInputConverter; + _commandOptionInputConverter = commandOptionInputConverter.GuardNotNull(nameof(commandOptionInputConverter)); } /// @@ -33,6 +33,10 @@ namespace CliFx.Services /// public void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input) { + command.GuardNotNull(nameof(command)); + schema.GuardNotNull(nameof(schema)); + input.GuardNotNull(nameof(input)); + // Set command options var isGroupNameDetected = false; var groupName = default(string); diff --git a/CliFx/Services/CommandInputParser.cs b/CliFx/Services/CommandInputParser.cs index 7a8dfad..5ff2bfc 100644 --- a/CliFx/Services/CommandInputParser.cs +++ b/CliFx/Services/CommandInputParser.cs @@ -15,6 +15,8 @@ namespace CliFx.Services /// public CommandInput ParseInput(IReadOnlyList commandLineArguments) { + commandLineArguments.GuardNotNull(nameof(commandLineArguments)); + // Initialize command name placeholder string commandName = null; diff --git a/CliFx/Services/CommandOptionInputConverter.cs b/CliFx/Services/CommandOptionInputConverter.cs index 11932a9..101a844 100644 --- a/CliFx/Services/CommandOptionInputConverter.cs +++ b/CliFx/Services/CommandOptionInputConverter.cs @@ -20,7 +20,7 @@ namespace CliFx.Services /// public CommandOptionInputConverter(IFormatProvider formatProvider) { - _formatProvider = formatProvider; + _formatProvider = formatProvider.GuardNotNull(nameof(formatProvider)); } /// @@ -244,6 +244,9 @@ namespace CliFx.Services /// public object ConvertOption(CommandOptionInput option, Type targetType) { + option.GuardNotNull(nameof(option)); + targetType.GuardNotNull(nameof(targetType)); + if (targetType != typeof(string) && targetType.IsEnumerable()) { var underlyingType = targetType.GetIEnumerableUnderlyingTypes().FirstOrDefault() ?? typeof(object); diff --git a/CliFx/Services/CommandSchemaResolver.cs b/CliFx/Services/CommandSchemaResolver.cs index 4c8551d..e6bd59a 100644 --- a/CliFx/Services/CommandSchemaResolver.cs +++ b/CliFx/Services/CommandSchemaResolver.cs @@ -30,8 +30,7 @@ namespace CliFx.Services /// public CommandSchema GetCommandSchema(Type commandType) { - if (!commandType.Implements(typeof(ICommand))) - throw new ArgumentException($"Command type must implement {nameof(ICommand)}.", nameof(commandType)); + commandType.GuardNotNull(nameof(commandType)); var attribute = commandType.GetCustomAttribute(); diff --git a/CliFx/Services/DelegateCommandFactory.cs b/CliFx/Services/DelegateCommandFactory.cs index 0d70df7..f11d2ff 100644 --- a/CliFx/Services/DelegateCommandFactory.cs +++ b/CliFx/Services/DelegateCommandFactory.cs @@ -1,4 +1,5 @@ using System; +using CliFx.Internal; namespace CliFx.Services { @@ -14,10 +15,14 @@ namespace CliFx.Services /// public DelegateCommandFactory(Func factoryMethod) { - _factoryMethod = factoryMethod; + _factoryMethod = factoryMethod.GuardNotNull(nameof(factoryMethod)); } /// - public ICommand CreateCommand(Type commandType) => _factoryMethod(commandType); + public ICommand CreateCommand(Type commandType) + { + commandType.GuardNotNull(nameof(commandType)); + return _factoryMethod(commandType); + } } } \ No newline at end of file diff --git a/CliFx/Services/Extensions.cs b/CliFx/Services/Extensions.cs index a962896..6a35c5e 100644 --- a/CliFx/Services/Extensions.cs +++ b/CliFx/Services/Extensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using CliFx.Internal; using CliFx.Models; namespace CliFx.Services @@ -14,13 +15,22 @@ namespace CliFx.Services /// Resolves command schemas for commands of specified types. /// public static IReadOnlyList GetCommandSchemas(this ICommandSchemaResolver resolver, - IReadOnlyList commandTypes) => commandTypes.Select(resolver.GetCommandSchema).ToArray(); + IReadOnlyList commandTypes) + { + resolver.GuardNotNull(nameof(resolver)); + commandTypes.GuardNotNull(nameof(commandTypes)); + + return commandTypes.Select(resolver.GetCommandSchema).ToArray(); + } /// /// Sets console foreground color, executes specified action, and sets the color back to the original value. /// 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; @@ -34,6 +44,9 @@ 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; @@ -45,7 +58,12 @@ 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) => + public static void WithColors(this IConsole console, ConsoleColor foregroundColor, ConsoleColor backgroundColor, Action action) + { + console.GuardNotNull(nameof(console)); + action.GuardNotNull(nameof(action)); + console.WithForegroundColor(foregroundColor, () => console.WithBackgroundColor(backgroundColor, action)); + } } } \ No newline at end of file diff --git a/CliFx/Services/TestConsole.cs b/CliFx/Services/TestConsole.cs index 5beec51..8be2485 100644 --- a/CliFx/Services/TestConsole.cs +++ b/CliFx/Services/TestConsole.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using CliFx.Internal; namespace CliFx.Services { @@ -39,9 +40,9 @@ namespace CliFx.Services /// public TestConsole(TextReader input, TextWriter output, TextWriter error) { - Input = input; - Output = output; - Error = error; + Input = input.GuardNotNull(nameof(input)); + Output = output.GuardNotNull(nameof(output)); + Error = error.GuardNotNull(nameof(error)); } ///