mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-12-31 02:08:08 +01:00
Separate Spectre.Console.Cli from Spectre.Console (#1850)
This commit is contained in:
@@ -1,7 +1,20 @@
|
||||
namespace Spectre.Console;
|
||||
namespace Spectre.Console.Testing;
|
||||
|
||||
internal static class ShouldlyExtensions
|
||||
/// <summary>
|
||||
/// Provides extensions for testing using the Shouldly-style fluent assertions.
|
||||
/// </summary>
|
||||
public static class ShouldlyExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs the specified action on the given object and then returns the object.
|
||||
/// Useful for fluent testing patterns where additional assertions or operations
|
||||
/// are chained together in a readable manner.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object.</typeparam>
|
||||
/// <param name="item">The object to operate on.</param>
|
||||
/// <param name="action">An action to perform on the object.</param>
|
||||
/// <returns>The original object, to allow further chaining.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="action"/> is null.</exception>
|
||||
[DebuggerStepThrough]
|
||||
public static T And<T>(this T item, Action<T> action)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace Spectre.Console.Testing;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for working with <see cref="TestConsole"/> in a testing context,
|
||||
/// including stack trace normalization for consistent and deterministic test output.
|
||||
/// </summary>
|
||||
public static partial class TestConsoleExtensions
|
||||
{
|
||||
private static readonly Regex _lineNumberRegex = new Regex(":\\d+", RegexOptions.Singleline);
|
||||
private static readonly Regex _filenameRegex = new Regex("\\sin\\s.*cs:nn", RegexOptions.Multiline);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given exception to the <see cref="TestConsole"/> and returns a normalized string
|
||||
/// representation of the exception, with file paths and line numbers sanitized.
|
||||
/// </summary>
|
||||
/// <param name="console">The <see cref="TestConsole"/> to write to.</param>
|
||||
/// <param name="ex">The exception to write and normalize.</param>
|
||||
/// <param name="formats">Optional formatting options for exception output.</param>
|
||||
/// <returns>A normalized string of the exception's output, safe for snapshot testing.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if the console's output buffer is not empty before writing the exception.
|
||||
/// </exception>
|
||||
public static string WriteNormalizedException(this TestConsole console, Exception ex, ExceptionFormats formats = ExceptionFormats.Default)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(console.Output))
|
||||
{
|
||||
throw new InvalidOperationException("Output buffer is not empty.");
|
||||
}
|
||||
|
||||
console.WriteException(ex, formats);
|
||||
return string.Join("\n", NormalizeStackTrace(console.Output)
|
||||
.NormalizeLineEndings()
|
||||
.Split(new char[] { '\n' })
|
||||
.Select(line => line.TrimEnd()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes a stack trace string by replacing line numbers with ":nn"
|
||||
/// and converting full file paths to a fixed placeholder path ("/xyz/filename.cs").
|
||||
/// </summary>
|
||||
/// <param name="text">The stack trace text to normalize.</param>
|
||||
/// <returns>A sanitized stack trace suitable for stable testing output.</returns>
|
||||
public static string NormalizeStackTrace(string text)
|
||||
{
|
||||
text = _lineNumberRegex.Replace(text, match =>
|
||||
{
|
||||
return ":nn";
|
||||
});
|
||||
|
||||
return _filenameRegex.Replace(text, match =>
|
||||
{
|
||||
var value = match.Value;
|
||||
var index = value.LastIndexOfAny(new[] { '\\', '/' });
|
||||
var filename = value.Substring(index + 1, value.Length - index - 1);
|
||||
|
||||
return $" in /xyz/{filename}";
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
namespace Spectre.Console.Testing;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extensions for <see cref="TestConsole"/>.
|
||||
/// </summary>
|
||||
public static partial class TestConsoleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the console's color system.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <param name="colors">The color system to use.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole Colors(this TestConsole console, ColorSystem colors)
|
||||
{
|
||||
console.Profile.Capabilities.ColorSystem = colors;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether or not ANSI is supported.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <param name="enable">Whether or not VT/ANSI control codes are supported.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole SupportsAnsi(this TestConsole console, bool enable)
|
||||
{
|
||||
console.Profile.Capabilities.Ansi = enable;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the console interactive.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole Interactive(this TestConsole console)
|
||||
{
|
||||
console.Profile.Capabilities.Interactive = true;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the console width.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <param name="width">The console width.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole Width(this TestConsole console, int width)
|
||||
{
|
||||
console.Profile.Width = width;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the console height.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <param name="width">The console height.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole Height(this TestConsole console, int width)
|
||||
{
|
||||
console.Profile.Height = width;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the console size.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <param name="size">The console size.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole Size(this TestConsole console, Size size)
|
||||
{
|
||||
console.Profile.Width = size.Width;
|
||||
console.Profile.Height = size.Height;
|
||||
return console;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turns on emitting of VT/ANSI sequences.
|
||||
/// </summary>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static TestConsole EmitAnsiSequences(this TestConsole console)
|
||||
{
|
||||
console.SetCursor(null);
|
||||
console.EmitAnsiSequences = true;
|
||||
return console;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user