This commit is contained in:
Alexey Golub
2019-06-29 22:02:41 +03:00
parent 79cf994386
commit 74ee927498
10 changed files with 60 additions and 84 deletions

View File

@@ -1,8 +1,6 @@
using System.Collections.Generic; using System.Threading.Tasks;
using System.Threading.Tasks;
using CliFx.Services; using CliFx.Services;
using CliFx.Tests.TestObjects; using CliFx.Tests.TestObjects;
using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace CliFx.Tests namespace CliFx.Tests
@@ -17,11 +15,13 @@ namespace CliFx.Tests
var command = new TestCommand(); var command = new TestCommand();
var expectedExitCode = await command.ExecuteAsync(); var expectedExitCode = await command.ExecuteAsync();
var commandResolverMock = new Mock<ICommandResolver>(); var commandOptionParser = new CommandOptionParser();
commandResolverMock.Setup(m => m.ResolveCommand(It.IsAny<IReadOnlyList<string>>())).Returns(command);
var commandResolver = commandResolverMock.Object;
var application = new CliApplication(commandResolver); var typeProvider = new TypeProvider(typeof(TestCommand));
var commandOptionConverter = new CommandOptionConverter();
var commandResolver = new CommandResolver(typeProvider, commandOptionConverter);
var application = new CliApplication(commandOptionParser, commandResolver);
// Act // Act
var exitCodeValue = await application.RunAsync(); var exitCodeValue = await application.RunAsync();

View File

@@ -8,10 +8,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Moq" Version="4.11.0" />
<PackageReference Include="CliWrap" Version="2.3.0" /> <PackageReference Include="CliWrap" Version="2.3.0" />
</ItemGroup> </ItemGroup>

View File

@@ -11,7 +11,7 @@ namespace CliFx.Tests
[TestFixture] [TestFixture]
public class CommandOptionConverterTests public class CommandOptionConverterTests
{ {
private static IEnumerable<TestCaseData> GetData_ConvertOption() private static IEnumerable<TestCaseData> GetTestCases_ConvertOption()
{ {
yield return new TestCaseData( yield return new TestCaseData(
new CommandOption("option", "value"), new CommandOption("option", "value"),
@@ -171,7 +171,7 @@ namespace CliFx.Tests
} }
[Test] [Test]
[TestCaseSource(nameof(GetData_ConvertOption))] [TestCaseSource(nameof(GetTestCases_ConvertOption))]
public void ConvertOption_Test(CommandOption option, Type targetType, object expectedConvertedValue) public void ConvertOption_Test(CommandOption option, Type targetType, object expectedConvertedValue)
{ {
// Arrange // Arrange
@@ -181,10 +181,13 @@ namespace CliFx.Tests
var convertedValue = converter.ConvertOption(option, targetType); var convertedValue = converter.ConvertOption(option, targetType);
// Assert // Assert
Assert.That(convertedValue, Is.EqualTo(expectedConvertedValue)); Assert.Multiple(() =>
{
Assert.That(convertedValue, Is.EqualTo(expectedConvertedValue));
if (convertedValue != null) if (convertedValue != null)
Assert.That(convertedValue, Is.AssignableTo(targetType)); Assert.That(convertedValue, Is.AssignableTo(targetType));
});
} }
} }
} }

View File

@@ -8,7 +8,7 @@ namespace CliFx.Tests
[TestFixture] [TestFixture]
public class CommandOptionParserTests public class CommandOptionParserTests
{ {
private static IEnumerable<TestCaseData> GetData_ParseOptions() private static IEnumerable<TestCaseData> GetTestCases_ParseOptions()
{ {
yield return new TestCaseData(new string[0], CommandOptionSet.Empty); yield return new TestCaseData(new string[0], CommandOptionSet.Empty);
@@ -154,7 +154,7 @@ namespace CliFx.Tests
} }
[Test] [Test]
[TestCaseSource(nameof(GetData_ParseOptions))] [TestCaseSource(nameof(GetTestCases_ParseOptions))]
public void ParseOptions_Test(IReadOnlyList<string> commandLineArguments, CommandOptionSet expectedCommandOptionSet) public void ParseOptions_Test(IReadOnlyList<string> commandLineArguments, CommandOptionSet expectedCommandOptionSet)
{ {
// Arrange // Arrange
@@ -164,17 +164,20 @@ namespace CliFx.Tests
var optionSet = parser.ParseOptions(commandLineArguments); var optionSet = parser.ParseOptions(commandLineArguments);
// Assert // Assert
Assert.That(optionSet.CommandName, Is.EqualTo(expectedCommandOptionSet.CommandName), "Command name"); Assert.Multiple(() =>
Assert.That(optionSet.Options.Count, Is.EqualTo(expectedCommandOptionSet.Options.Count), "Option count");
for (var i = 0; i < optionSet.Options.Count; i++)
{ {
Assert.That(optionSet.Options[i].Name, Is.EqualTo(expectedCommandOptionSet.Options[i].Name), Assert.That(optionSet.CommandName, Is.EqualTo(expectedCommandOptionSet.CommandName), "Command name");
$"Option[{i}] name"); Assert.That(optionSet.Options.Count, Is.EqualTo(expectedCommandOptionSet.Options.Count), "Option count");
Assert.That(optionSet.Options[i].Values, Is.EqualTo(expectedCommandOptionSet.Options[i].Values), for (var i = 0; i < optionSet.Options.Count; i++)
$"Option[{i}] values"); {
} Assert.That(optionSet.Options[i].Name, Is.EqualTo(expectedCommandOptionSet.Options[i].Name),
$"Option[{i}] name");
Assert.That(optionSet.Options[i].Values, Is.EqualTo(expectedCommandOptionSet.Options[i].Values),
$"Option[{i}] values");
}
});
} }
} }
} }

View File

@@ -3,7 +3,6 @@ using CliFx.Exceptions;
using CliFx.Models; using CliFx.Models;
using CliFx.Services; using CliFx.Services;
using CliFx.Tests.TestObjects; using CliFx.Tests.TestObjects;
using Moq;
using NUnit.Framework; using NUnit.Framework;
namespace CliFx.Tests namespace CliFx.Tests
@@ -11,7 +10,7 @@ namespace CliFx.Tests
[TestFixture] [TestFixture]
public class CommandResolverTests public class CommandResolverTests
{ {
private static IEnumerable<TestCaseData> GetData_ResolveCommand() private static IEnumerable<TestCaseData> GetTestCases_ResolveCommand()
{ {
yield return new TestCaseData( yield return new TestCaseData(
new CommandOptionSet(new[] new CommandOptionSet(new[]
@@ -48,34 +47,28 @@ namespace CliFx.Tests
} }
[Test] [Test]
[TestCaseSource(nameof(GetData_ResolveCommand))] [TestCaseSource(nameof(GetTestCases_ResolveCommand))]
public void ResolveCommand_Test(CommandOptionSet commandOptionSet, TestCommand expectedCommand) public void ResolveCommand_Test(CommandOptionSet commandOptionSet, TestCommand expectedCommand)
{ {
// Arrange // Arrange
var commandTypes = new[] {typeof(TestCommand)}; var typeProvider = new TypeProvider(typeof(TestCommand));
var typeProviderMock = new Mock<ITypeProvider>();
typeProviderMock.Setup(m => m.GetTypes()).Returns(commandTypes);
var typeProvider = typeProviderMock.Object;
var optionParserMock = new Mock<ICommandOptionParser>();
optionParserMock.Setup(m => m.ParseOptions(It.IsAny<IReadOnlyList<string>>())).Returns(commandOptionSet);
var optionParser = optionParserMock.Object;
var optionConverter = new CommandOptionConverter(); var optionConverter = new CommandOptionConverter();
var resolver = new CommandResolver(typeProvider, optionParser, optionConverter); var resolver = new CommandResolver(typeProvider, optionConverter);
// Act // Act
var command = resolver.ResolveCommand() as TestCommand; var command = resolver.ResolveCommand(commandOptionSet) as TestCommand;
// Assert // Assert
Assert.That(command, Is.Not.Null); Assert.Multiple(() =>
Assert.That(command.StringOption, Is.EqualTo(expectedCommand.StringOption), nameof(command.StringOption)); {
Assert.That(command.IntOption, Is.EqualTo(expectedCommand.IntOption), nameof(command.IntOption)); Assert.That(command, Is.Not.Null);
Assert.That(command.StringOption, Is.EqualTo(expectedCommand.StringOption), nameof(command.StringOption));
Assert.That(command.IntOption, Is.EqualTo(expectedCommand.IntOption), nameof(command.IntOption));
});
} }
private static IEnumerable<TestCaseData> GetData_ResolveCommand_IsRequired() private static IEnumerable<TestCaseData> GetTestCases_ResolveCommand_IsRequired()
{ {
yield return new TestCaseData(CommandOptionSet.Empty); yield return new TestCaseData(CommandOptionSet.Empty);
@@ -88,26 +81,17 @@ namespace CliFx.Tests
} }
[Test] [Test]
[TestCaseSource(nameof(GetData_ResolveCommand_IsRequired))] [TestCaseSource(nameof(GetTestCases_ResolveCommand_IsRequired))]
public void ResolveCommand_IsRequired_Test(CommandOptionSet commandOptionSet) public void ResolveCommand_IsRequired_Test(CommandOptionSet commandOptionSet)
{ {
// Arrange // Arrange
var commandTypes = new[] {typeof(TestCommand)}; var typeProvider = new TypeProvider(typeof(TestCommand));
var typeProviderMock = new Mock<ITypeProvider>();
typeProviderMock.Setup(m => m.GetTypes()).Returns(commandTypes);
var typeProvider = typeProviderMock.Object;
var optionParserMock = new Mock<ICommandOptionParser>();
optionParserMock.Setup(m => m.ParseOptions(It.IsAny<IReadOnlyList<string>>())).Returns(commandOptionSet);
var optionParser = optionParserMock.Object;
var optionConverter = new CommandOptionConverter(); var optionConverter = new CommandOptionConverter();
var resolver = new CommandResolver(typeProvider, optionParser, optionConverter); var resolver = new CommandResolver(typeProvider, optionConverter);
// Act & Assert // Act & Assert
Assert.Throws<CommandResolveException>(() => resolver.ResolveCommand()); Assert.Throws<CommandResolveException>(() => resolver.ResolveCommand(commandOptionSet));
} }
} }
} }

View File

@@ -7,25 +7,26 @@ namespace CliFx
{ {
public partial class CliApplication : ICliApplication public partial class CliApplication : ICliApplication
{ {
private readonly ICommandOptionParser _commandOptionParser;
private readonly ICommandResolver _commandResolver; private readonly ICommandResolver _commandResolver;
public CliApplication(ICommandResolver commandResolver) public CliApplication(ICommandOptionParser commandOptionParser, ICommandResolver commandResolver)
{ {
_commandOptionParser = commandOptionParser;
_commandResolver = commandResolver; _commandResolver = commandResolver;
} }
public CliApplication() public CliApplication()
: this(GetDefaultCommandResolver(Assembly.GetCallingAssembly())) : this(new CommandOptionParser(), GetDefaultCommandResolver(Assembly.GetCallingAssembly()))
{ {
} }
public async Task<int> RunAsync(IReadOnlyList<string> commandLineArguments) public async Task<int> RunAsync(IReadOnlyList<string> commandLineArguments)
{ {
// Resolve and execute command var optionSet = _commandOptionParser.ParseOptions(commandLineArguments);
var command = _commandResolver.ResolveCommand(commandLineArguments); var command = _commandResolver.ResolveCommand(optionSet);
var exitCode = await command.ExecuteAsync();
// TODO: print message if error? var exitCode = await command.ExecuteAsync();
return exitCode.Value; return exitCode.Value;
} }
@@ -36,10 +37,9 @@ namespace CliFx
private static ICommandResolver GetDefaultCommandResolver(Assembly assembly) private static ICommandResolver GetDefaultCommandResolver(Assembly assembly)
{ {
var typeProvider = TypeProvider.FromAssembly(assembly); var typeProvider = TypeProvider.FromAssembly(assembly);
var commandOptionParser = new CommandOptionParser();
var commandOptionConverter = new CommandOptionConverter(); var commandOptionConverter = new CommandOptionConverter();
return new CommandResolver(typeProvider, commandOptionParser, commandOptionConverter); return new CommandResolver(typeProvider, commandOptionConverter);
} }
} }
} }

View File

@@ -11,14 +11,11 @@ namespace CliFx.Services
public class CommandResolver : ICommandResolver public class CommandResolver : ICommandResolver
{ {
private readonly ITypeProvider _typeProvider; private readonly ITypeProvider _typeProvider;
private readonly ICommandOptionParser _commandOptionParser;
private readonly ICommandOptionConverter _commandOptionConverter; private readonly ICommandOptionConverter _commandOptionConverter;
public CommandResolver(ITypeProvider typeProvider, public CommandResolver(ITypeProvider typeProvider, ICommandOptionConverter commandOptionConverter)
ICommandOptionParser commandOptionParser, ICommandOptionConverter commandOptionConverter)
{ {
_typeProvider = typeProvider; _typeProvider = typeProvider;
_commandOptionParser = commandOptionParser;
_commandOptionConverter = commandOptionConverter; _commandOptionConverter = commandOptionConverter;
} }
@@ -71,10 +68,8 @@ namespace CliFx.Services
$"Apply {nameof(CommandAttribute)} to give command a name."); $"Apply {nameof(CommandAttribute)} to give command a name.");
} }
public Command ResolveCommand(IReadOnlyList<string> commandLineArguments) public Command ResolveCommand(CommandOptionSet optionSet)
{ {
var optionSet = _commandOptionParser.ParseOptions(commandLineArguments);
// Get command type // Get command type
var commandType = !optionSet.CommandName.IsNullOrWhiteSpace() var commandType = !optionSet.CommandName.IsNullOrWhiteSpace()
? GetCommandType(optionSet.CommandName) ? GetCommandType(optionSet.CommandName)

View File

@@ -1,7 +0,0 @@
namespace CliFx.Services
{
public static class Extensions
{
public static Command ResolveCommand(this ICommandResolver commandResolver) => commandResolver.ResolveCommand(new string[0]);
}
}

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic; using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
public interface ICommandResolver public interface ICommandResolver
{ {
Command ResolveCommand(IReadOnlyList<string> commandLineArguments); Command ResolveCommand(CommandOptionSet optionSet);
} }
} }

View File

@@ -26,7 +26,6 @@ To be added with a stable release...
## Libraries used ## Libraries used
- [Moq](https://github.com/Moq/moq4)
- [NUnit](https://github.com/nunit/nunit) - [NUnit](https://github.com/nunit/nunit)
## Donate ## Donate