mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-04 10:35:27 +08:00 
			
		
		
		
	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:
		@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Spectre.Console;
 | 
					namespace Spectre.Console;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -21,6 +23,23 @@ public static partial class AnsiConsole
 | 
				
			|||||||
        return prompt.Show(Console);
 | 
					        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>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Displays a prompt to the user.
 | 
					    /// Displays a prompt to the user.
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -32,6 +51,18 @@ public static partial class AnsiConsole
 | 
				
			|||||||
        return new TextPrompt<T>(prompt).Show(Console);
 | 
					        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>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Displays a prompt to the user with a given default.
 | 
					    /// Displays a prompt to the user with a given default.
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -46,6 +77,21 @@ public static partial class AnsiConsole
 | 
				
			|||||||
            .Show(Console);
 | 
					            .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>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Displays a prompt with two choices, yes or no.
 | 
					    /// Displays a prompt with two choices, yes or no.
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -60,4 +106,20 @@ public static partial class AnsiConsole
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        .Show(Console);
 | 
					        .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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Spectre.Console;
 | 
					namespace Spectre.Console;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
@@ -64,4 +66,68 @@ public static partial class AnsiConsoleExtensions
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        .Show(console);
 | 
					        .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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,19 +2,29 @@ namespace Spectre.Console.Tests.Unit;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public partial class AnsiConsoleTests
 | 
					public partial class AnsiConsoleTests
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public sealed class Prompt
 | 
					    public sealed class Confirm
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        [Theory]
 | 
					        [Theory]
 | 
				
			||||||
        [InlineData(true, true)]
 | 
					        [InlineData(true, true, true)]
 | 
				
			||||||
        [InlineData(false, false)]
 | 
					        [InlineData(false, true, true)]
 | 
				
			||||||
        public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, bool defaultValue)
 | 
					        [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
 | 
					            // Given
 | 
				
			||||||
            var console = new TestConsole().EmitAnsiSequences();
 | 
					            var console = new TestConsole().EmitAnsiSequences();
 | 
				
			||||||
            console.Input.PushKey(ConsoleKey.Enter);
 | 
					            console.Input.PushKey(ConsoleKey.Enter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // When
 | 
					            // 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
 | 
					            // Then
 | 
				
			||||||
            result.ShouldBe(expected);
 | 
					            result.ShouldBe(expected);
 | 
				
			||||||
@@ -23,29 +33,49 @@ public partial class AnsiConsoleTests
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public sealed class Ask
 | 
					    public sealed class Ask
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        [Fact]
 | 
					        [Theory]
 | 
				
			||||||
        public void Should_Return_Correct_DateTime_When_Asked_PL_Culture()
 | 
					        [InlineData(true)]
 | 
				
			||||||
 | 
					        [InlineData(false)]
 | 
				
			||||||
 | 
					        public async Task Should_Return_Correct_DateTime_When_Asked_PL_Culture(bool async)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Given
 | 
					            // Given
 | 
				
			||||||
            var console = new TestConsole().EmitAnsiSequences();
 | 
					            var console = new TestConsole().EmitAnsiSequences();
 | 
				
			||||||
            console.Input.PushTextWithEnter("1/2/1998");
 | 
					            console.Input.PushTextWithEnter("1/2/1998");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // When
 | 
					            // 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
 | 
					            // Then
 | 
				
			||||||
            dateTime.ShouldBe(new DateTime(1998, 2, 1));
 | 
					            dateTime.ShouldBe(new DateTime(1998, 2, 1));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Theory]
 | 
				
			||||||
        public void Should_Return_Correct_DateTime_When_Asked_US_Culture()
 | 
					        [InlineData(true)]
 | 
				
			||||||
 | 
					        [InlineData(false)]
 | 
				
			||||||
 | 
					        public async Task Should_Return_Correct_DateTime_When_Asked_US_Culture(bool async)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Given
 | 
					            // Given
 | 
				
			||||||
            var console = new TestConsole().EmitAnsiSequences();
 | 
					            var console = new TestConsole().EmitAnsiSequences();
 | 
				
			||||||
            console.Input.PushTextWithEnter("2/1/1998");
 | 
					            console.Input.PushTextWithEnter("2/1/1998");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // When
 | 
					            // 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
 | 
					            // Then
 | 
				
			||||||
            dateTime.ShouldBe(new DateTime(1998, 2, 1));
 | 
					            dateTime.ShouldBe(new DateTime(1998, 2, 1));
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user