Async overloads for AnsiConsole Prompt/Ask/Confirm. (#1194)

* Add async overloads for Prompt/Ask/Confirm.

* Added unit test coverage - AskAsync, ConfirmAsync

* Reordered methods to group non-async/async of the same tests together

---------

Co-authored-by: Frank Ray <52075808+FrankRay78@users.noreply.github.com>
This commit is contained in:
Tom Deseyn 2024-11-28 11:56:19 +01:00 committed by GitHub
parent 92daeb739d
commit 29ab313bb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 169 additions and 11 deletions

View File

@ -1,3 +1,5 @@
using System.Threading.Tasks;
namespace Spectre.Console;
/// <summary>
@ -21,6 +23,23 @@ public static partial class AnsiConsole
return prompt.Show(Console);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="prompt">The prompt to display.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> PromptAsync<T>(IPrompt<T> prompt, CancellationToken cancellationToken = default)
{
if (prompt is null)
{
throw new ArgumentNullException(nameof(prompt));
}
return prompt.ShowAsync(Console, cancellationToken);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
@ -32,6 +51,18 @@ public static partial class AnsiConsole
return new TextPrompt<T>(prompt).Show(Console);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> AskAsync<T>(string prompt, CancellationToken cancellationToken = default)
{
return new TextPrompt<T>(prompt).ShowAsync(Console, cancellationToken);
}
/// <summary>
/// Displays a prompt to the user with a given default.
/// </summary>
@ -46,6 +77,21 @@ public static partial class AnsiConsole
.Show(Console);
}
/// <summary>
/// Displays a prompt to the user with a given default.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> AskAsync<T>(string prompt, T defaultValue, CancellationToken cancellationToken = default)
{
return new TextPrompt<T>(prompt)
.DefaultValue(defaultValue)
.ShowAsync(Console, cancellationToken);
}
/// <summary>
/// Displays a prompt with two choices, yes or no.
/// </summary>
@ -60,4 +106,20 @@ public static partial class AnsiConsole
}
.Show(Console);
}
/// <summary>
/// Displays a prompt with two choices, yes or no.
/// </summary>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="defaultValue">Specifies the default answer.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
public static Task<bool> ConfirmAsync(string prompt, bool defaultValue = true, CancellationToken cancellationToken = default)
{
return new ConfirmationPrompt(prompt)
{
DefaultValue = defaultValue,
}
.ShowAsync(Console, cancellationToken);
}
}

View File

@ -1,3 +1,5 @@
using System.Threading.Tasks;
namespace Spectre.Console;
/// <summary>
@ -64,4 +66,68 @@ public static partial class AnsiConsoleExtensions
}
.Show(console);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt to display.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> PromptAsync<T>(this IAnsiConsole console, IPrompt<T> prompt, CancellationToken cancellationToken = default)
{
if (prompt is null)
{
throw new ArgumentNullException(nameof(prompt));
}
return prompt.ShowAsync(console, cancellationToken);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> AskAsync<T>(this IAnsiConsole console, string prompt, CancellationToken cancellationToken = default)
{
return new TextPrompt<T>(prompt).ShowAsync(console, cancellationToken);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="culture">Specific CultureInfo to use when converting input.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The prompt input result.</returns>
public static Task<T> AskAsync<T>(this IAnsiConsole console, string prompt, CultureInfo? culture, CancellationToken cancellationToken = default)
{
var textPrompt = new TextPrompt<T>(prompt);
textPrompt.Culture = culture;
return textPrompt.ShowAsync(console, cancellationToken);
}
/// <summary>
/// Displays a prompt with two choices, yes or no.
/// </summary>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt markup text.</param>
/// <param name="defaultValue">Specifies the default answer.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
public static Task<bool> ConfirmAsync(this IAnsiConsole console, string prompt, bool defaultValue = true, CancellationToken cancellationToken = default)
{
return new ConfirmationPrompt(prompt)
{
DefaultValue = defaultValue,
}
.ShowAsync(console, cancellationToken);
}
}

View File

@ -2,19 +2,29 @@ namespace Spectre.Console.Tests.Unit;
public partial class AnsiConsoleTests
{
public sealed class Prompt
public sealed class Confirm
{
[Theory]
[InlineData(true, true)]
[InlineData(false, false)]
public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, bool defaultValue)
[InlineData(true, true, true)]
[InlineData(false, true, true)]
[InlineData(true, false, false)]
[InlineData(false, false, false)]
public async Task Should_Return_Default_Value_If_Nothing_Is_Entered(bool async, bool defaultValue, bool expected)
{
// Given
var console = new TestConsole().EmitAnsiSequences();
console.Input.PushKey(ConsoleKey.Enter);
// When
var result = console.Confirm("Want some prompt?", defaultValue);
bool result;
if (async)
{
result = await console.ConfirmAsync("Want some prompt?", defaultValue);
}
else
{
result = console.Confirm("Want some prompt?", defaultValue);
}
// Then
result.ShouldBe(expected);
@ -23,29 +33,49 @@ public partial class AnsiConsoleTests
public sealed class Ask
{
[Fact]
public void Should_Return_Correct_DateTime_When_Asked_PL_Culture()
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task Should_Return_Correct_DateTime_When_Asked_PL_Culture(bool async)
{
// Given
var console = new TestConsole().EmitAnsiSequences();
console.Input.PushTextWithEnter("1/2/1998");
// When
var dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
DateTime dateTime;
if (async)
{
dateTime = await console.AskAsync<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
}
else
{
dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
}
// Then
dateTime.ShouldBe(new DateTime(1998, 2, 1));
}
[Fact]
public void Should_Return_Correct_DateTime_When_Asked_US_Culture()
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task Should_Return_Correct_DateTime_When_Asked_US_Culture(bool async)
{
// Given
var console = new TestConsole().EmitAnsiSequences();
console.Input.PushTextWithEnter("2/1/1998");
// When
var dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
DateTime dateTime;
if (async)
{
dateTime = await console.AskAsync<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
}
else
{
dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
}
// Then
dateTime.ShouldBe(new DateTime(1998, 2, 1));