mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-12-18 08:15:48 +08:00
Add new test framework for consoles
This commit is contained in:
committed by
Phil Scott
parent
f5a9c0ca26
commit
04efd1719c
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="ICommandInterceptor"/> that triggers a callback when invoked.
|
||||
/// </summary>
|
||||
public sealed class CallbackCommandInterceptor : ICommandInterceptor
|
||||
{
|
||||
private readonly Action<CommandContext, CommandSettings> _callback;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CallbackCommandInterceptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="callback">The callback to call when the interceptor is invoked.</param>
|
||||
public CallbackCommandInterceptor(Action<CommandContext, CommandSettings> callback)
|
||||
{
|
||||
_callback = callback ?? throw new ArgumentNullException(nameof(callback));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Intercept(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
_callback(context, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/Spectre.Console.Testing/Cli/CommandAppFailure.cs
Normal file
29
src/Spectre.Console.Testing/Cli/CommandAppFailure.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="CommandApp"/> runtime failure.
|
||||
/// </summary>
|
||||
public sealed class CommandAppFailure
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the exception that was thrown.
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console output.
|
||||
/// </summary>
|
||||
public string Output { get; }
|
||||
|
||||
internal CommandAppFailure(Exception exception, string output)
|
||||
{
|
||||
Exception = exception ?? throw new ArgumentNullException(nameof(exception));
|
||||
Output = output.NormalizeLineEndings()
|
||||
.TrimLines()
|
||||
.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/Spectre.Console.Testing/Cli/CommandAppResult.cs
Normal file
43
src/Spectre.Console.Testing/Cli/CommandAppResult.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the result of a completed <see cref="CommandApp"/> run.
|
||||
/// </summary>
|
||||
public sealed class CommandAppResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the exit code.
|
||||
/// </summary>
|
||||
public int ExitCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console output.
|
||||
/// </summary>
|
||||
public string Output { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command context.
|
||||
/// </summary>
|
||||
public CommandContext? Context { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command settings.
|
||||
/// </summary>
|
||||
public CommandSettings? Settings { get; }
|
||||
|
||||
internal CommandAppResult(int exitCode, string output, CommandContext? context, CommandSettings? settings)
|
||||
{
|
||||
ExitCode = exitCode;
|
||||
Output = output ?? string.Empty;
|
||||
Context = context;
|
||||
Settings = settings;
|
||||
|
||||
Output = Output
|
||||
.NormalizeLineEndings()
|
||||
.TrimLines()
|
||||
.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/Spectre.Console.Testing/Cli/CommandAppTester.cs
Normal file
112
src/Spectre.Console.Testing/Cli/CommandAppTester.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Testing
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="CommandApp"/> test harness.
|
||||
/// </summary>
|
||||
public sealed class CommandAppTester
|
||||
{
|
||||
private Action<CommandApp>? _appConfiguration;
|
||||
private Action<IConfigurator>? _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default command.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The default command type.</typeparam>
|
||||
public void SetDefaultCommand<T>()
|
||||
where T : class, ICommand
|
||||
{
|
||||
_appConfiguration = (app) => app.SetDefaultCommand<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the command application.
|
||||
/// </summary>
|
||||
/// <param name="action">The configuration action.</param>
|
||||
public void Configure(Action<IConfigurator> action)
|
||||
{
|
||||
if (_configuration != null)
|
||||
{
|
||||
throw new InvalidOperationException("The command app harnest have already been configured.");
|
||||
}
|
||||
|
||||
_configuration = action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command application and expects an exception of a specific type to be thrown.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected exception type.</typeparam>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The information about the failure.</returns>
|
||||
public CommandAppFailure RunAndCatch<T>(params string[] args)
|
||||
where T : Exception
|
||||
{
|
||||
var console = new TestConsole().Width(int.MaxValue);
|
||||
|
||||
try
|
||||
{
|
||||
Run(args, console, c => c.PropagateExceptions());
|
||||
throw new InvalidOperationException("Expected an exception to be thrown, but there was none.");
|
||||
}
|
||||
catch (T ex)
|
||||
{
|
||||
return new CommandAppFailure(ex, console.Output);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Expected an exception of type '{typeof(T).FullName}' to be thrown, "
|
||||
+ $"but received {ex.GetType().FullName}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command application.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The result.</returns>
|
||||
public CommandAppResult Run(params string[] args)
|
||||
{
|
||||
var console = new TestConsole().Width(int.MaxValue);
|
||||
return Run(args, console);
|
||||
}
|
||||
|
||||
private CommandAppResult Run(string[] args, TestConsole console, Action<IConfigurator>? config = null)
|
||||
{
|
||||
CommandContext? context = null;
|
||||
CommandSettings? settings = null;
|
||||
|
||||
var app = new CommandApp();
|
||||
_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 = app.Run(args);
|
||||
|
||||
var output = console.Output
|
||||
.NormalizeLineEndings()
|
||||
.TrimLines()
|
||||
.Trim();
|
||||
|
||||
return new CommandAppResult(result, output, context, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user