mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Cleanup
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<IsTestProject>true</IsTestProject>
|
|
||||||
<CollectCoverage>true</CollectCoverage>
|
<CollectCoverage>true</CollectCoverage>
|
||||||
<CoverletOutputFormat>opencover</CoverletOutputFormat>
|
<CoverletOutputFormat>opencover</CoverletOutputFormat>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<IsTestProject>true</IsTestProject>
|
|
||||||
<CollectCoverage>true</CollectCoverage>
|
<CollectCoverage>true</CollectCoverage>
|
||||||
<CoverletOutputFormat>opencover</CoverletOutputFormat>
|
<CoverletOutputFormat>opencover</CoverletOutputFormat>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -496,6 +496,83 @@ public class Command : ICommand
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Option_binding_supports_multiple_inheritance_through_default_interface_members()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
public static class SharedContext
|
||||||
|
{
|
||||||
|
public static int Foo { get; set; }
|
||||||
|
|
||||||
|
public static bool Bar { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasFoo : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption(""foo"")]
|
||||||
|
public int Foo
|
||||||
|
{
|
||||||
|
get => SharedContext.Foo;
|
||||||
|
set => SharedContext.Foo = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasBar : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption(""bar"")]
|
||||||
|
public bool Bar
|
||||||
|
{
|
||||||
|
get => SharedContext.Bar;
|
||||||
|
set => SharedContext.Bar = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasBaz : ICommand
|
||||||
|
{
|
||||||
|
public string Baz { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : IHasFoo, IHasBar, IHasBaz
|
||||||
|
{
|
||||||
|
[CommandOption(""baz"")]
|
||||||
|
public string Baz { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(""Foo = "" + SharedContext.Foo);
|
||||||
|
console.Output.WriteLine(""Bar = "" + SharedContext.Bar);
|
||||||
|
console.Output.WriteLine(""Baz = "" + Baz);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
");
|
||||||
|
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] { "--foo", "42", "--bar", "--baz", "xyz" }
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().Be(0);
|
||||||
|
stdOut.Should().ConsistOfLines(
|
||||||
|
"Foo = 42",
|
||||||
|
"Bar = True",
|
||||||
|
"Baz = xyz"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Option_binding_does_not_consider_a_negative_number_as_an_option_name_or_short_name()
|
public async Task Option_binding_does_not_consider_a_negative_number_as_an_option_name_or_short_name()
|
||||||
{
|
{
|
||||||
@@ -704,64 +781,4 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Option_bound_using_interfaces_for_multiple_inheritance_should_work()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
|
||||||
// language=cs
|
|
||||||
@"
|
|
||||||
public static class FooBarLogger
|
|
||||||
{
|
|
||||||
public static bool Foo { get; set; } = false;
|
|
||||||
public static bool Bar { get; set; } = false;
|
|
||||||
}
|
|
||||||
public interface IOptionBar : ICommand
|
|
||||||
{
|
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public bool Bar
|
|
||||||
{
|
|
||||||
get => FooBarLogger.Bar;
|
|
||||||
set => FooBarLogger.Bar = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public interface IOptionFoo : ICommand
|
|
||||||
{
|
|
||||||
[CommandOption(""foo"")]
|
|
||||||
public bool Foo
|
|
||||||
{
|
|
||||||
get => FooBarLogger.Foo;
|
|
||||||
set => FooBarLogger.Foo = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
public class Command : IOptionFoo, IOptionBar
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine($""Foo: { FooBarLogger.Foo }"");
|
|
||||||
console.Output.WriteLine($""Bar: { FooBarLogger.Bar }"");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
|
||||||
.AddCommand(commandType)
|
|
||||||
.UseConsole(FakeConsole)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var exitCode = await application.RunAsync(
|
|
||||||
new[] {"--foo" , "--bar"});
|
|
||||||
|
|
||||||
var stdOut = FakeConsole.ReadOutputString();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
exitCode.Should().Be(0);
|
|
||||||
stdOut.Trim().Should().Be("Foo: True" + Environment.NewLine + "Bar: True");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -87,10 +87,20 @@ internal partial class CommandSchema
|
|||||||
? new[] {OptionSchema.HelpOption, OptionSchema.VersionOption}
|
? new[] {OptionSchema.HelpOption, OptionSchema.VersionOption}
|
||||||
: new[] {OptionSchema.HelpOption};
|
: new[] {OptionSchema.HelpOption};
|
||||||
|
|
||||||
// Include interface members for multiple inheritance
|
var properties = type
|
||||||
// If interface inherits from ICommand, it will be included
|
// Get properties directly on command type
|
||||||
var interfaces = type.GetInterfaces().Where(i => i != typeof(ICommand) && typeof(ICommand).IsAssignableFrom(i) );
|
.GetProperties()
|
||||||
var properties = type.GetProperties().Concat(interfaces.SelectMany(i => i.GetProperties())).ToArray();
|
// Get non-abstract properties on interfaces (to support default interfaces members)
|
||||||
|
.Union(type
|
||||||
|
.GetInterfaces()
|
||||||
|
// Only interfaces implementing ICommand for explicitness
|
||||||
|
.Where(i => typeof(ICommand).IsAssignableFrom(i) && i != typeof(ICommand))
|
||||||
|
.SelectMany(i => i
|
||||||
|
.GetProperties()
|
||||||
|
.Where(p => !p.GetMethod.IsAbstract && !p.SetMethod.IsAbstract)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
var parameterSchemas = properties
|
var parameterSchemas = properties
|
||||||
.Select(ParameterSchema.TryResolve)
|
.Select(ParameterSchema.TryResolve)
|
||||||
|
|||||||
Reference in New Issue
Block a user