mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Refactor
This commit is contained in:
@@ -1,33 +1,36 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Attributes;
|
||||||
|
using CliFx.Models;
|
||||||
using CliFx.Services;
|
using CliFx.Services;
|
||||||
using CliFx.Tests.TestObjects;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests
|
||||||
{
|
{
|
||||||
|
public partial class CliApplicationTests
|
||||||
|
{
|
||||||
|
[DefaultCommand]
|
||||||
|
public class TestCommand : Command
|
||||||
|
{
|
||||||
|
public override ExitCode Execute() => new ExitCode(13);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CliApplicationTests
|
public partial class CliApplicationTests
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public async Task RunAsync_Test()
|
public async Task RunAsync_Test()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var command = new TestCommand();
|
var application = new CliApplication(
|
||||||
var expectedExitCode = await command.ExecuteAsync();
|
new CommandOptionParser(),
|
||||||
|
new CommandResolver(new[] {typeof(TestCommand)}, new CommandOptionConverter()));
|
||||||
var commandOptionParser = new CommandOptionParser();
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.That(exitCodeValue, Is.EqualTo(expectedExitCode.Value), "Exit code");
|
Assert.That(exitCodeValue, Is.EqualTo(13), "Exit code");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,44 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CliFx.Models;
|
using CliFx.Models;
|
||||||
using CliFx.Services;
|
using CliFx.Services;
|
||||||
using CliFx.Tests.TestObjects;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests
|
||||||
{
|
{
|
||||||
|
public partial class CommandOptionConverterTests
|
||||||
|
{
|
||||||
|
public enum TestEnum
|
||||||
|
{
|
||||||
|
Value1,
|
||||||
|
Value2,
|
||||||
|
Value3
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestStringConstructable
|
||||||
|
{
|
||||||
|
public string Value { get; }
|
||||||
|
|
||||||
|
public TestStringConstructable(string value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestStringParseable
|
||||||
|
{
|
||||||
|
public string Value { get; }
|
||||||
|
|
||||||
|
private TestStringParseable(string value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestStringParseable Parse(string value) => new TestStringParseable(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CommandOptionConverterTests
|
public partial class CommandOptionConverterTests
|
||||||
{
|
{
|
||||||
private static IEnumerable<TestCaseData> GetTestCases_ConvertOption()
|
private static IEnumerable<TestCaseData> GetTestCases_ConvertOption()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using CliFx.Attributes;
|
||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Models;
|
using CliFx.Models;
|
||||||
using CliFx.Services;
|
using CliFx.Services;
|
||||||
using CliFx.Tests.TestObjects;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests
|
||||||
{
|
{
|
||||||
|
public partial class CommandResolverTests
|
||||||
|
{
|
||||||
|
[DefaultCommand]
|
||||||
|
public class TestCommand : Command
|
||||||
|
{
|
||||||
|
[CommandOption("int", 'i', IsRequired = true)]
|
||||||
|
public int IntOption { get; set; } = 24;
|
||||||
|
|
||||||
|
[CommandOption("str", 's')] public string StringOption { get; set; } = "foo bar";
|
||||||
|
|
||||||
|
public override ExitCode Execute() => new ExitCode(IntOption, StringOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CommandResolverTests
|
public partial class CommandResolverTests
|
||||||
{
|
{
|
||||||
private static IEnumerable<TestCaseData> GetTestCases_ResolveCommand()
|
private static IEnumerable<TestCaseData> GetTestCases_ResolveCommand()
|
||||||
{
|
{
|
||||||
@@ -36,14 +50,6 @@ namespace CliFx.Tests
|
|||||||
}),
|
}),
|
||||||
new TestCommand {IntOption = 13}
|
new TestCommand {IntOption = 13}
|
||||||
);
|
);
|
||||||
|
|
||||||
yield return new TestCaseData(
|
|
||||||
new CommandOptionSet("command", new[]
|
|
||||||
{
|
|
||||||
new CommandOption("int", "13")
|
|
||||||
}),
|
|
||||||
new TestCommand {IntOption = 13}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -51,10 +57,7 @@ namespace CliFx.Tests
|
|||||||
public void ResolveCommand_Test(CommandOptionSet commandOptionSet, TestCommand expectedCommand)
|
public void ResolveCommand_Test(CommandOptionSet commandOptionSet, TestCommand expectedCommand)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var typeProvider = new TypeProvider(typeof(TestCommand));
|
var resolver = new CommandResolver(new[] {typeof(TestCommand)}, new CommandOptionConverter());
|
||||||
var optionConverter = new CommandOptionConverter();
|
|
||||||
|
|
||||||
var resolver = new CommandResolver(typeProvider, optionConverter);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var command = resolver.ResolveCommand(commandOptionSet) as TestCommand;
|
var command = resolver.ResolveCommand(commandOptionSet) as TestCommand;
|
||||||
@@ -85,10 +88,7 @@ namespace CliFx.Tests
|
|||||||
public void ResolveCommand_IsRequired_Test(CommandOptionSet commandOptionSet)
|
public void ResolveCommand_IsRequired_Test(CommandOptionSet commandOptionSet)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var typeProvider = new TypeProvider(typeof(TestCommand));
|
var resolver = new CommandResolver(new[] {typeof(TestCommand)}, new CommandOptionConverter());
|
||||||
var optionConverter = new CommandOptionConverter();
|
|
||||||
|
|
||||||
var resolver = new CommandResolver(typeProvider, optionConverter);
|
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
Assert.Throws<CommandResolveException>(() => resolver.ResolveCommand(commandOptionSet));
|
Assert.Throws<CommandResolveException>(() => resolver.ResolveCommand(commandOptionSet));
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
using CliFx.Attributes;
|
|
||||||
using CliFx.Models;
|
|
||||||
|
|
||||||
namespace CliFx.Tests.TestObjects
|
|
||||||
{
|
|
||||||
[DefaultCommand]
|
|
||||||
[Command("command")]
|
|
||||||
public class TestCommand : Command
|
|
||||||
{
|
|
||||||
[CommandOption("int", 'i', IsRequired = true)]
|
|
||||||
public int IntOption { get; set; } = 24;
|
|
||||||
|
|
||||||
[CommandOption("str", 's')]
|
|
||||||
public string StringOption { get; set; } = "foo bar";
|
|
||||||
|
|
||||||
public override ExitCode Execute() => new ExitCode(IntOption, StringOption);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace CliFx.Tests.TestObjects
|
|
||||||
{
|
|
||||||
public enum TestEnum
|
|
||||||
{
|
|
||||||
Value1,
|
|
||||||
Value2,
|
|
||||||
Value3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace CliFx.Tests.TestObjects
|
|
||||||
{
|
|
||||||
public struct TestStringConstructable
|
|
||||||
{
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
public TestStringConstructable(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace CliFx.Tests.TestObjects
|
|
||||||
{
|
|
||||||
public partial struct TestStringParseable
|
|
||||||
{
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
private TestStringParseable(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial struct TestStringParseable
|
|
||||||
{
|
|
||||||
public static TestStringParseable Parse(string value) => new TestStringParseable(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Services;
|
using CliFx.Services;
|
||||||
|
|
||||||
namespace CliFx
|
namespace CliFx
|
||||||
{
|
{
|
||||||
public partial class CliApplication : ICliApplication
|
public class CliApplication : ICliApplication
|
||||||
{
|
{
|
||||||
private readonly ICommandOptionParser _commandOptionParser;
|
private readonly ICommandOptionParser _commandOptionParser;
|
||||||
private readonly ICommandResolver _commandResolver;
|
private readonly ICommandResolver _commandResolver;
|
||||||
@@ -17,7 +16,7 @@ namespace CliFx
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CliApplication()
|
public CliApplication()
|
||||||
: this(new CommandOptionParser(), GetDefaultCommandResolver(Assembly.GetCallingAssembly()))
|
: this(new CommandOptionParser(), new CommandResolver(new CommandOptionConverter()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,15 +30,4 @@ namespace CliFx
|
|||||||
return exitCode.Value;
|
return exitCode.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class CliApplication
|
|
||||||
{
|
|
||||||
private static ICommandResolver GetDefaultCommandResolver(Assembly assembly)
|
|
||||||
{
|
|
||||||
var typeProvider = TypeProvider.FromAssembly(assembly);
|
|
||||||
var commandOptionConverter = new CommandOptionConverter();
|
|
||||||
|
|
||||||
return new CommandResolver(typeProvider, commandOptionConverter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace CliFx
|
namespace CliFx
|
||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static Task<int> RunAsync(this ICliApplication application) =>
|
public static Task<int> RunAsync(this ICliApplication application) => application.RunAsync(new string[0]);
|
||||||
application.RunAsync(Environment.GetCommandLineArgs().Skip(1).ToArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ namespace CliFx.Internal
|
|||||||
// Derives from Command
|
// Derives from Command
|
||||||
type.IsDerivedFrom(typeof(Command)) &&
|
type.IsDerivedFrom(typeof(Command)) &&
|
||||||
// Marked with DefaultCommandAttribute or CommandAttribute
|
// Marked with DefaultCommandAttribute or CommandAttribute
|
||||||
(type.IsDefined(typeof(DefaultCommandAttribute)) || type.IsDefined(typeof(CommandAttribute)));
|
type.IsDefined(typeof(CommandAttribute));
|
||||||
|
|
||||||
public static CommandType Initialize(Type type)
|
public static CommandType Initialize(Type type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Internal;
|
using CliFx.Internal;
|
||||||
@@ -8,18 +9,23 @@ using CliFx.Models;
|
|||||||
|
|
||||||
namespace CliFx.Services
|
namespace CliFx.Services
|
||||||
{
|
{
|
||||||
public class CommandResolver : ICommandResolver
|
public partial class CommandResolver : ICommandResolver
|
||||||
{
|
{
|
||||||
private readonly ITypeProvider _typeProvider;
|
private readonly IReadOnlyList<Type> _availableTypes;
|
||||||
private readonly ICommandOptionConverter _commandOptionConverter;
|
private readonly ICommandOptionConverter _commandOptionConverter;
|
||||||
|
|
||||||
public CommandResolver(ITypeProvider typeProvider, ICommandOptionConverter commandOptionConverter)
|
public CommandResolver(IReadOnlyList<Type> availableTypes, ICommandOptionConverter commandOptionConverter)
|
||||||
{
|
{
|
||||||
_typeProvider = typeProvider;
|
_availableTypes = availableTypes;
|
||||||
_commandOptionConverter = commandOptionConverter;
|
_commandOptionConverter = commandOptionConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<CommandType> GetCommandTypes() => CommandType.GetCommandTypes(_typeProvider.GetTypes());
|
public CommandResolver(ICommandOptionConverter commandOptionConverter)
|
||||||
|
: this(GetDefaultAvailableTypes(), commandOptionConverter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<CommandType> GetCommandTypes() => CommandType.GetCommandTypes(_availableTypes);
|
||||||
|
|
||||||
private CommandType GetDefaultCommandType()
|
private CommandType GetDefaultCommandType()
|
||||||
{
|
{
|
||||||
@@ -100,4 +106,9 @@ namespace CliFx.Services
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public partial class CommandResolver
|
||||||
|
{
|
||||||
|
private static IReadOnlyList<Type> GetDefaultAvailableTypes() => Assembly.GetEntryAssembly()?.GetExportedTypes() ?? new Type[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace CliFx.Services
|
|
||||||
{
|
|
||||||
public interface ITypeProvider
|
|
||||||
{
|
|
||||||
IReadOnlyList<Type> GetTypes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace CliFx.Services
|
|
||||||
{
|
|
||||||
public partial class TypeProvider : ITypeProvider
|
|
||||||
{
|
|
||||||
private readonly IReadOnlyList<Type> _types;
|
|
||||||
|
|
||||||
public TypeProvider(IReadOnlyList<Type> types)
|
|
||||||
{
|
|
||||||
_types = types;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeProvider(params Type[] types)
|
|
||||||
: this((IReadOnlyList<Type>) types)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public IReadOnlyList<Type> GetTypes() => _types;
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class TypeProvider
|
|
||||||
{
|
|
||||||
public static TypeProvider FromAssembly(Assembly assembly) => new TypeProvider(assembly.GetExportedTypes());
|
|
||||||
|
|
||||||
public static TypeProvider FromAssemblies(IReadOnlyList<Assembly> assemblies) =>
|
|
||||||
new TypeProvider(assemblies.SelectMany(a => a.ExportedTypes).ToArray());
|
|
||||||
|
|
||||||
public static TypeProvider FromAssemblies(params Assembly[] assemblies) => FromAssemblies((IReadOnlyList<Assembly>) assemblies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user