From 49eab04a9ca6aa64bb630a7c8ad10f8a045d0d82 Mon Sep 17 00:00:00 2001 From: Frank Ray <52075808+FrankRay78@users.noreply.github.com> Date: Tue, 16 May 2023 12:11:29 +0100 Subject: [PATCH 1/3] Intitial version of asynch command unit tests --- .../Cli/CommandAppTester.cs | 46 ++++++++++++++++ .../Data/Commands/AsynchronousCommand.cs | 28 ++++++++++ .../Data/Commands/ThrowingCommand.cs | 6 +-- .../Settings/AsynchronousCommandSettings.cs | 8 +++ .../Data/Settings/ThrowingCommandSettings.cs | 5 ++ .../Unit/CommandAppTests.Async.cs | 52 +++++++++++++++++++ 6 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 test/Spectre.Console.Cli.Tests/Data/Commands/AsynchronousCommand.cs create mode 100644 test/Spectre.Console.Cli.Tests/Data/Settings/AsynchronousCommandSettings.cs create mode 100644 test/Spectre.Console.Cli.Tests/Data/Settings/ThrowingCommandSettings.cs create mode 100644 test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs diff --git a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs index d06ccd4de..f53f60cc4 100644 --- a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs +++ b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs @@ -135,6 +135,52 @@ private CommandAppResult Run(string[] args, TestConsole console, Action + /// Runs the command application asynchronously. + /// + /// The arguments. + /// The result. + public async Task RunAsync(params string[] args) + { + var console = new TestConsole().Width(int.MaxValue); + return await RunAsync(args, console); + } + + private async Task RunAsync(string[] args, TestConsole console, Action? config = null) + { + CommandContext? context = null; + CommandSettings? settings = null; + + var app = new CommandApp(Registrar); + _appConfiguration?.Invoke(app); + + if (_configuration != null) + { + app.Configure(_configuration); + } + + if (config != null) + { + app.Configure(config); + } + + app.Configure(c => c.ConfigureConsole(console)); + app.Configure(c => c.SetInterceptor(new CallbackCommandInterceptor((ctx, s) => + { + context = ctx; + settings = s; + }))); + + var result = await app.RunAsync(args); + var output = console.Output .NormalizeLineEndings() .TrimLines() diff --git a/test/Spectre.Console.Cli.Tests/Data/Commands/AsynchronousCommand.cs b/test/Spectre.Console.Cli.Tests/Data/Commands/AsynchronousCommand.cs new file mode 100644 index 000000000..100d187e9 --- /dev/null +++ b/test/Spectre.Console.Cli.Tests/Data/Commands/AsynchronousCommand.cs @@ -0,0 +1,28 @@ +namespace Spectre.Console.Tests.Data; + +public sealed class AsynchronousCommand : AsyncCommand +{ + private readonly IAnsiConsole _console; + + public AsynchronousCommand(IAnsiConsole console) + { + _console = console; + } + + public async override Task ExecuteAsync(CommandContext context, AsynchronousCommandSettings settings) + { + // Simulate a long running asynchronous task + await Task.Delay(200); + + if (settings.ThrowException) + { + throw new Exception($"Throwing exception asynchronously"); + } + else + { + _console.WriteLine($"Finished executing asynchronously"); + } + + return 0; + } +} diff --git a/test/Spectre.Console.Cli.Tests/Data/Commands/ThrowingCommand.cs b/test/Spectre.Console.Cli.Tests/Data/Commands/ThrowingCommand.cs index 686bf4a47..480452502 100644 --- a/test/Spectre.Console.Cli.Tests/Data/Commands/ThrowingCommand.cs +++ b/test/Spectre.Console.Cli.Tests/Data/Commands/ThrowingCommand.cs @@ -6,8 +6,4 @@ public override int Execute(CommandContext context, ThrowingCommandSettings sett { throw new InvalidOperationException("W00t?"); } -} - -public sealed class ThrowingCommandSettings : CommandSettings -{ -} +} \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Data/Settings/AsynchronousCommandSettings.cs b/test/Spectre.Console.Cli.Tests/Data/Settings/AsynchronousCommandSettings.cs new file mode 100644 index 000000000..b7bb8e26f --- /dev/null +++ b/test/Spectre.Console.Cli.Tests/Data/Settings/AsynchronousCommandSettings.cs @@ -0,0 +1,8 @@ +namespace Spectre.Console.Tests.Data; + +public sealed class AsynchronousCommandSettings : CommandSettings +{ + [CommandOption("--ThrowException")] + [DefaultValue(false)] + public bool ThrowException { get; set; } +} \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Data/Settings/ThrowingCommandSettings.cs b/test/Spectre.Console.Cli.Tests/Data/Settings/ThrowingCommandSettings.cs new file mode 100644 index 000000000..88a28ffa5 --- /dev/null +++ b/test/Spectre.Console.Cli.Tests/Data/Settings/ThrowingCommandSettings.cs @@ -0,0 +1,5 @@ +namespace Spectre.Console.Tests.Data; + +public sealed class ThrowingCommandSettings : CommandSettings +{ +} diff --git a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs new file mode 100644 index 000000000..d84f5889f --- /dev/null +++ b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs @@ -0,0 +1,52 @@ +namespace Spectre.Console.Tests.Unit.Cli; + +public sealed partial class CommandAppTests +{ + public sealed class Async + { + [Fact] + public async void Should_Execute_Command_Asynchronously() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand(); + app.Configure(config => + { + config.PropagateExceptions(); + }); + + // When + var result = await app.RunAsync(); + + // Then + result.ExitCode.ShouldBe(0); + result.Output.ShouldBe("Finished executing asynchronously"); + } + + [Fact] + public async void Should_Throw_Exception_Asynchronously() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand(); + app.Configure(config => + { + config.PropagateExceptions(); + }); + + // When + var result = await Record.ExceptionAsync(async () => + await app.RunAsync(new[] + { + "--ThrowException", + "true", + })); + + // Then + result.ShouldBeOfType().And(ex => + { + ex.Message.ShouldBe("Throwing exception asynchronously"); + }); + } + } +} \ No newline at end of file From 7d2dd89c2260cab6e3e59ad5febbe69837632281 Mon Sep 17 00:00:00 2001 From: Frank Ray <52075808+FrankRay78@users.noreply.github.com> Date: Wed, 17 May 2023 11:14:59 +0100 Subject: [PATCH 2/3] Added test case --- .../Unit/CommandAppTests.Async.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs index d84f5889f..5bc1df856 100644 --- a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs +++ b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs @@ -23,6 +23,25 @@ public async void Should_Execute_Command_Asynchronously() result.Output.ShouldBe("Finished executing asynchronously"); } + [Fact] + public async void Should_Handle_Exception_Asynchronously() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand(); + + // When + var result = await app.RunAsync(new[] + { + "--ThrowException", + "true", + }); + + // Then + result.ExitCode.ShouldBe(-1); + } + + [Fact] public async void Should_Throw_Exception_Asynchronously() { From 0f15b96ba0d32cb9cf0b80b7b0758eda1c226e18 Mon Sep 17 00:00:00 2001 From: Frank Ray <52075808+FrankRay78@users.noreply.github.com> Date: Wed, 17 May 2023 11:26:09 +0100 Subject: [PATCH 3/3] Fix style cop warning --- test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs index 5bc1df856..ee88b0b25 100644 --- a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs +++ b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Async.cs @@ -41,7 +41,6 @@ public async void Should_Handle_Exception_Asynchronously() result.ExitCode.ShouldBe(-1); } - [Fact] public async void Should_Throw_Exception_Asynchronously() {