mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
264 lines
7.8 KiB
C#
264 lines
7.8 KiB
C#
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using CliFx.Tests.Utils;
|
|
using CliFx.Tests.Utils.Extensions;
|
|
using FluentAssertions;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace CliFx.Tests;
|
|
|
|
public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
|
|
{
|
|
[Fact]
|
|
public async Task I_can_bind_a_parameter_to_a_property_and_get_the_value_from_the_corresponding_argument()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1)]
|
|
public required string Bar { get; init; }
|
|
|
|
public ValueTask ExecuteAsync(IConsole console)
|
|
{
|
|
console.WriteLine("Foo = " + Foo);
|
|
console.WriteLine("Bar = " + Bar);
|
|
|
|
return default;
|
|
}
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(["one", "two"], new Dictionary<string, string>());
|
|
|
|
// Assert
|
|
exitCode.Should().Be(0);
|
|
|
|
var stdOut = FakeConsole.ReadOutputString();
|
|
stdOut.Should().ConsistOfLines("Foo = one", "Bar = two");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task I_can_bind_a_parameter_to_a_non_scalar_property_and_get_values_from_the_remaining_non_option_arguments()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1)]
|
|
public required string Bar { get; init; }
|
|
|
|
[CommandParameter(2)]
|
|
public required IReadOnlyList<string> Baz { get; init; }
|
|
|
|
[CommandOption("boo")]
|
|
public string? Boo { get; init; }
|
|
|
|
public ValueTask ExecuteAsync(IConsole console)
|
|
{
|
|
console.WriteLine("Foo = " + Foo);
|
|
console.WriteLine("Bar = " + Bar);
|
|
|
|
foreach (var i in Baz)
|
|
console.WriteLine("Baz = " + i);
|
|
|
|
return default;
|
|
}
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(
|
|
["one", "two", "three", "four", "five", "--boo", "xxx"],
|
|
new Dictionary<string, string>()
|
|
);
|
|
|
|
// Assert
|
|
exitCode.Should().Be(0);
|
|
|
|
var stdOut = FakeConsole.ReadOutputString();
|
|
stdOut
|
|
.Should()
|
|
.ConsistOfLines("Foo = one", "Bar = two", "Baz = three", "Baz = four", "Baz = five");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task I_can_try_to_bind_a_parameter_to_a_property_and_get_an_error_if_the_user_does_not_provide_the_corresponding_argument()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1)]
|
|
public required string Bar { get; init; }
|
|
|
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(["one"], new Dictionary<string, string>());
|
|
|
|
// Assert
|
|
exitCode.Should().NotBe(0);
|
|
|
|
var stdErr = FakeConsole.ReadErrorString();
|
|
stdErr.Should().Contain("Missing required parameter(s)");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task I_can_try_to_bind_a_parameter_to_a_non_scalar_property_and_get_an_error_if_the_user_does_not_provide_at_least_one_corresponding_argument()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1)]
|
|
public required IReadOnlyList<string> Bar { get; init; }
|
|
|
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(["one"], new Dictionary<string, string>());
|
|
|
|
// Assert
|
|
exitCode.Should().NotBe(0);
|
|
|
|
var stdErr = FakeConsole.ReadErrorString();
|
|
stdErr.Should().Contain("Missing required parameter(s)");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task I_can_bind_a_non_required_parameter_to_a_property_and_get_no_value_if_the_user_does_not_provide_the_corresponding_argument()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1, IsRequired = false)]
|
|
public string? Bar { get; init; } = "xyz";
|
|
|
|
public ValueTask ExecuteAsync(IConsole console)
|
|
{
|
|
console.WriteLine("Foo = " + Foo);
|
|
console.WriteLine("Bar = " + Bar);
|
|
|
|
return default;
|
|
}
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(["abc"], new Dictionary<string, string>());
|
|
|
|
// Assert
|
|
exitCode.Should().Be(0);
|
|
|
|
var stdOut = FakeConsole.ReadOutputString();
|
|
stdOut.Should().ConsistOfLines("Foo = abc", "Bar = xyz");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task I_can_try_to_bind_parameters_and_get_an_error_if_the_user_provides_too_many_arguments()
|
|
{
|
|
// Arrange
|
|
var commandType = DynamicCommandBuilder.Compile(
|
|
// lang=csharp
|
|
"""
|
|
[Command]
|
|
public class Command : ICommand
|
|
{
|
|
[CommandParameter(0)]
|
|
public required string Foo { get; init; }
|
|
|
|
[CommandParameter(1)]
|
|
public required string Bar { get; init; }
|
|
|
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
}
|
|
"""
|
|
);
|
|
|
|
var application = new CliApplicationBuilder()
|
|
.AddCommand(commandType)
|
|
.UseConsole(FakeConsole)
|
|
.Build();
|
|
|
|
// Act
|
|
var exitCode = await application.RunAsync(
|
|
["one", "two", "three"],
|
|
new Dictionary<string, string>()
|
|
);
|
|
|
|
// Assert
|
|
exitCode.Should().NotBe(0);
|
|
|
|
var stdErr = FakeConsole.ReadErrorString();
|
|
stdErr.Should().Contain("Unexpected parameter(s)");
|
|
}
|
|
}
|