Fixes #4243 - ConsoleDriverFacade.CreateClipboard now honors FakeDriver.FakeBehaviors.UseFakeClipboard (#4244)

* updatd ConsoleDriverFacade.CreateClipboard to honor FakeDriver.FakeBehaviors.UseFakeClipboard

* Code cleanup of fake driver v2
This commit is contained in:
Tig
2025-09-12 12:32:31 -07:00
committed by GitHub
parent e869f842e3
commit 18b602e980
15 changed files with 292 additions and 331 deletions

View File

@@ -1,5 +1,4 @@
using System.Diagnostics; #nullable enable
namespace Terminal.Gui.App; namespace Terminal.Gui.App;
/// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary> /// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary>
@@ -20,10 +19,10 @@ namespace Terminal.Gui.App;
/// </remarks> /// </remarks>
public static class Clipboard public static class Clipboard
{ {
private static string _contents = string.Empty; private static string? _contents = string.Empty;
/// <summary>Gets (copies from) or sets (pastes to) the contents of the OS clipboard.</summary> /// <summary>Gets (copies from) or sets (pastes to) the contents of the OS clipboard.</summary>
public static string Contents public static string? Contents
{ {
get get
{ {
@@ -31,13 +30,8 @@ public static class Clipboard
{ {
if (IsSupported) if (IsSupported)
{ {
string clipData = Application.Driver?.Clipboard.GetClipboardData (); // throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
string? clipData = Application.Driver?.Clipboard?.GetClipboardData () ?? string.Empty;
if (clipData is null)
{
// throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
clipData = string.Empty;
}
_contents = clipData; _contents = clipData;
} }
@@ -55,12 +49,9 @@ public static class Clipboard
{ {
if (IsSupported) if (IsSupported)
{ {
if (value is null) value ??= string.Empty;
{
value = string.Empty;
}
Application.Driver?.Clipboard.SetClipboardData (value); Application.Driver?.Clipboard?.SetClipboardData (value);
} }
_contents = value; _contents = value;
@@ -74,126 +65,5 @@ public static class Clipboard
/// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary> /// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary>
/// <remarks></remarks> /// <remarks></remarks>
public static bool IsSupported => Application.Driver?.Clipboard.IsSupported ?? false; public static bool IsSupported => Application.Driver?.Clipboard?.IsSupported ?? false;
}
/// <summary>Copies the _contents of the OS clipboard to <paramref name="result"/> if possible.</summary>
/// <param name="result">The _contents of the OS clipboard if successful, <see cref="string.Empty"/> if not.</param>
/// <returns><see langword="true"/> the OS clipboard was retrieved, <see langword="false"/> otherwise.</returns>
public static bool TryGetClipboardData (out string result)
{
if (IsSupported && Application.Driver!.Clipboard.TryGetClipboardData (out result))
{
_contents = result;
return true;
}
result = string.Empty;
return false;
}
/// <summary>Pastes the <paramref name="text"/> to the OS clipboard if possible.</summary>
/// <param name="text">The text to paste to the OS clipboard.</param>
/// <returns><see langword="true"/> the OS clipboard was set, <see langword="false"/> otherwise.</returns>
public static bool TrySetClipboardData (string text)
{
if (IsSupported && Application.Driver!.Clipboard.TrySetClipboardData (text))
{
_contents = text;
return true;
}
return false;
}
}
/// <summary>
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
/// </summary>
internal static class ClipboardProcessRunner
{
public static (int exitCode, string result) Bash (
string commandLine,
string inputText = "",
bool waitForOutput = false
)
{
var arguments = $"-c \"{commandLine}\"";
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
return (exitCode, result.TrimEnd ());
}
public static bool DoubleWaitForExit (this Process process)
{
bool result = process.WaitForExit (500);
if (result)
{
process.WaitForExit ();
}
return result;
}
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
public static (int exitCode, string result) Process (
string cmd,
string arguments,
string input = null,
bool waitForOutput = true
)
{
var output = string.Empty;
using (var process = new Process
{
StartInfo = new()
{
FileName = cmd,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
}
})
{
TaskCompletionSource<bool> eventHandled = new ();
process.Start ();
if (!string.IsNullOrEmpty (input))
{
process.StandardInput.Write (input);
process.StandardInput.Close ();
}
if (!process.WaitForExit (5000))
{
var timeoutError =
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
throw new TimeoutException (timeoutError);
}
if (waitForOutput && process.StandardOutput.Peek () != -1)
{
output = process.StandardOutput.ReadToEnd ();
}
if (process.ExitCode > 0)
{
output = $@"Process failed to run. Command line: {cmd} {arguments}.
Output: {output}
Error: {process.StandardError.ReadToEnd ()}";
}
return (process.ExitCode, output);
}
}
}

View File

@@ -0,0 +1,79 @@
#nullable enable
using System.Diagnostics;
namespace Terminal.Gui.App;
/// <summary>
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
/// </summary>
internal static class ClipboardProcessRunner
{
public static (int exitCode, string result) Bash (
string commandLine,
string inputText = "",
bool waitForOutput = false
)
{
var arguments = $"-c \"{commandLine}\"";
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
return (exitCode, result.TrimEnd ());
}
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
public static (int exitCode, string result) Process (
string cmd,
string arguments,
string? input = null,
bool waitForOutput = true
)
{
var output = string.Empty;
using var process = new Process ();
process.StartInfo = new()
{
FileName = cmd,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
};
TaskCompletionSource<bool> eventHandled = new ();
process.Start ();
if (!string.IsNullOrEmpty (input))
{
process.StandardInput.Write (input);
process.StandardInput.Close ();
}
if (!process.WaitForExit (5000))
{
var timeoutError =
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
throw new TimeoutException (timeoutError);
}
if (waitForOutput && process.StandardOutput.Peek () != -1)
{
output = process.StandardOutput.ReadToEnd ();
}
if (process.ExitCode > 0)
{
output = $@"Process failed to run. Command line: {cmd} {arguments}.
Output: {output}
Error: {process.StandardError.ReadToEnd ()}";
}
return (process.ExitCode, output);
}
}

View File

@@ -1,4 +1,5 @@
// #nullable enable
//
// FakeDriver.cs: A fake IConsoleDriver for unit tests. // FakeDriver.cs: A fake IConsoleDriver for unit tests.
// //
@@ -36,7 +37,7 @@ public class FakeDriver : ConsoleDriver
public bool UseFakeClipboard { get; internal set; } public bool UseFakeClipboard { get; internal set; }
} }
public static Behaviors FakeBehaviors = new (); public static Behaviors FakeBehaviors { get; } = new ();
public override bool SupportsTrueColor => false; public override bool SupportsTrueColor => false;
/// <inheritdoc /> /// <inheritdoc />
@@ -47,8 +48,8 @@ public class FakeDriver : ConsoleDriver
public FakeDriver () public FakeDriver ()
{ {
Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH; base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
if (FakeBehaviors.UseFakeClipboard) if (FakeBehaviors.UseFakeClipboard)
{ {
@@ -87,7 +88,7 @@ public class FakeDriver : ConsoleDriver
FakeConsole.Clear (); FakeConsole.Clear ();
} }
private FakeMainLoop _mainLoopDriver; private FakeMainLoop? _mainLoopDriver;
public override MainLoop Init () public override MainLoop Init ()
{ {
@@ -124,7 +125,7 @@ public class FakeDriver : ConsoleDriver
for (int row = top; row < rows; row++) for (int row = top; row < rows; row++)
{ {
if (!_dirtyLines [row]) if (!_dirtyLines! [row])
{ {
continue; continue;
} }
@@ -144,7 +145,7 @@ public class FakeDriver : ConsoleDriver
for (; col < cols; col++) for (; col < cols; col++)
{ {
if (!Contents [row, col].IsDirty) if (!Contents! [row, col].IsDirty)
{ {
if (output.Length > 0) if (output.Length > 0)
{ {
@@ -168,7 +169,7 @@ public class FakeDriver : ConsoleDriver
lastCol = col; lastCol = col;
} }
Attribute attr = Contents [row, col].Attribute.Value; Attribute attr = Contents [row, col].Attribute!.Value;
// Performance: Only send the escape sequence if the attribute has changed. // Performance: Only send the escape sequence if the attribute has changed.
if (attr != redrawAttr) if (attr != redrawAttr)
@@ -209,18 +210,18 @@ public class FakeDriver : ConsoleDriver
//SetCursorVisibility (savedVisibility); //SetCursorVisibility (savedVisibility);
void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth) void WriteToConsole (StringBuilder outputSb, ref int lastColumn, int row, ref int outputWidth)
{ {
FakeConsole.CursorTop = row; FakeConsole.CursorTop = row;
FakeConsole.CursorLeft = lastCol; FakeConsole.CursorLeft = lastColumn;
foreach (char c in output.ToString ()) foreach (char c in outputSb.ToString ())
{ {
FakeConsole.Write (c); FakeConsole.Write (c);
} }
output.Clear (); outputSb.Clear ();
lastCol += outputWidth; lastColumn += outputWidth;
outputWidth = 0; outputWidth = 0;
} }
@@ -506,7 +507,7 @@ public class FakeDriver : ConsoleDriver
public class FakeClipboard : ClipboardBase public class FakeClipboard : ClipboardBase
{ {
public Exception FakeException; public Exception? FakeException { get; set; }
private readonly bool _isSupportedAlwaysFalse; private readonly bool _isSupportedAlwaysFalse;
private string _contents = string.Empty; private string _contents = string.Empty;
@@ -536,19 +537,14 @@ public class FakeDriver : ConsoleDriver
return _contents; return _contents;
} }
protected override void SetClipboardDataImpl (string text) protected override void SetClipboardDataImpl (string? text)
{ {
if (text is null)
{
throw new ArgumentNullException (nameof (text));
}
if (FakeException is { }) if (FakeException is { })
{ {
throw FakeException; throw FakeException;
} }
_contents = text; _contents = text ?? throw new ArgumentNullException (nameof (text));
} }
} }

View File

@@ -1,5 +1,5 @@
using System.Runtime.InteropServices; #nullable enable
using Microsoft.Extensions.Logging; using System.Runtime.InteropServices;
namespace Terminal.Gui.Drivers; namespace Terminal.Gui.Drivers;
@@ -11,7 +11,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
private CursorVisibility _lastCursor = CursorVisibility.Default; private CursorVisibility _lastCursor = CursorVisibility.Default;
/// <summary>The event fired when the terminal is resized.</summary> /// <summary>The event fired when the terminal is resized.</summary>
public event EventHandler<SizeChangedEventArgs> SizeChanged; public event EventHandler<SizeChangedEventArgs>? SizeChanged;
public IInputProcessor InputProcessor { get; } public IInputProcessor InputProcessor { get; }
public IOutputBuffer OutputBuffer => _outputBuffer; public IOutputBuffer OutputBuffer => _outputBuffer;
@@ -48,6 +48,13 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
private void CreateClipboard () private void CreateClipboard ()
{ {
if (FakeDriver.FakeBehaviors.UseFakeClipboard)
{
Clipboard = new FakeDriver.FakeClipboard ();
return;
}
PlatformID p = Environment.OSVersion.Platform; PlatformID p = Environment.OSVersion.Platform;
if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
@@ -88,7 +95,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
/// to. /// to.
/// </summary> /// </summary>
/// <value>The rectangle describing the of <see cref="Clip"/> region.</value> /// <value>The rectangle describing the of <see cref="Clip"/> region.</value>
public Region Clip public Region? Clip
{ {
get => _outputBuffer.Clip; get => _outputBuffer.Clip;
set => _outputBuffer.Clip = value; set => _outputBuffer.Clip = value;
@@ -114,7 +121,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
/// The contents of the application output. The driver outputs this buffer to the terminal. /// The contents of the application output. The driver outputs this buffer to the terminal.
/// <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks> /// <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
/// </summary> /// </summary>
public Cell [,] Contents public Cell [,]? Contents
{ {
get => _outputBuffer.Contents; get => _outputBuffer.Contents;
set => _outputBuffer.Contents = value; set => _outputBuffer.Contents = value;
@@ -229,7 +236,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
/// <summary> /// <summary>
/// Raised each time <see cref="ConsoleDriver.ClearContents"/> is called. For benchmarking. /// Raised each time <see cref="ConsoleDriver.ClearContents"/> is called. For benchmarking.
/// </summary> /// </summary>
public event EventHandler<EventArgs> ClearedContents; public event EventHandler<EventArgs>? ClearedContents;
/// <summary> /// <summary>
/// Fills the specified rectangle with the specified rune, using <see cref="ConsoleDriver.CurrentAttribute"/> /// Fills the specified rectangle with the specified rune, using <see cref="ConsoleDriver.CurrentAttribute"/>
@@ -397,7 +404,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
} }
/// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary> /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary>
public event EventHandler<Key> KeyDown; public event EventHandler<Key>? KeyDown;
/// <summary>Event fired when a key is released.</summary> /// <summary>Event fired when a key is released.</summary>
/// <remarks> /// <remarks>
@@ -405,10 +412,10 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
/// processing is /// processing is
/// complete. /// complete.
/// </remarks> /// </remarks>
public event EventHandler<Key> KeyUp; public event EventHandler<Key>? KeyUp;
/// <summary>Event fired when a mouse event occurs.</summary> /// <summary>Event fired when a mouse event occurs.</summary>
public event EventHandler<MouseEventArgs> MouseEvent; public event EventHandler<MouseEventArgs>? MouseEvent;
/// <summary>Simulates a key press.</summary> /// <summary>Simulates a key press.</summary>
/// <param name="keyChar">The key character.</param> /// <param name="keyChar">The key character.</param>

View File

@@ -1,4 +1,5 @@
namespace Terminal.Gui.Drivers; #nullable enable
namespace Terminal.Gui.Drivers;
/// <summary> /// <summary>
/// Interface for v2 driver abstraction layer /// Interface for v2 driver abstraction layer

View File

@@ -12,7 +12,7 @@ public interface IOutputBuffer
/// <summary> /// <summary>
/// The contents of the application output. The driver outputs this buffer to the terminal when UpdateScreen is called. /// The contents of the application output. The driver outputs this buffer to the terminal when UpdateScreen is called.
/// </summary> /// </summary>
Cell [,] Contents { get; set; } Cell [,]? Contents { get; set; }
/// <summary> /// <summary>
/// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject /// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject

View File

@@ -0,0 +1,45 @@
#nullable enable
using System.Drawing;
using TerminalGuiFluentTesting;
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591
public class FakeApplicationFactory
{
/// <summary>
/// Creates an initialized fake application which will be cleaned up when result object
/// is disposed.
/// </summary>
/// <returns></returns>
public IDisposable SetupFakeApplication ()
{
var cts = new CancellationTokenSource ();
var fakeInput = new FakeNetInput (cts.Token);
FakeOutput output = new ();
output.Size = new (25, 25);
IApplication origApp = ApplicationImpl.Instance;
var sizeMonitor = new FakeSizeMonitor ();
var v2 = new ApplicationV2 (new FakeNetComponentFactory (fakeInput, output, sizeMonitor));
ApplicationImpl.ChangeInstance (v2);
v2.Init (null, "v2net");
ConsoleDriverFacade<ConsoleKeyInfo> d = (ConsoleDriverFacade<ConsoleKeyInfo>)Application.Driver!;
sizeMonitor.SizeChanging += (_, e) =>
{
if (e.Size != null)
{
Size s = e.Size.Value;
output.Size = s;
d.OutputBuffer.SetWindowSize (s.Width, s.Height);
}
};
return new FakeApplicationLifecycle (origApp, cts);
}
}

View File

@@ -0,0 +1,16 @@
#nullable enable
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591
internal class FakeApplicationLifecycle (IApplication origApp, CancellationTokenSource hardStop) : IDisposable
{
/// <inheritdoc/>
public void Dispose ()
{
hardStop.Cancel ();
Application.Top?.Dispose ();
Application.Shutdown ();
ApplicationImpl.ChangeInstance (origApp);
}
}

View File

@@ -0,0 +1,20 @@
#nullable enable
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591
public class FakeDriverFactory
{
/// <summary>
/// Creates a new instance of <see cref="FakeDriverV2"/> using default options
/// </summary>
/// <returns></returns>
public IFakeDriverV2 Create ()
{
return new FakeDriverV2 (
new (),
new (),
new (),
() => DateTime.Now,
new ());
}
}

View File

@@ -0,0 +1,58 @@
#nullable enable
using System.Collections.Concurrent;
using System.Drawing;
using TerminalGuiFluentTesting;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Terminal.Gui.Drivers;
/// <summary>
/// Implementation of <see cref="IConsoleDriver"/> that uses fake input/output.
/// This is a lightweight alternative to <see cref="GuiTestContext"/> (if you don't
/// need the entire application main loop running).
/// </summary>
internal class FakeDriverV2 : ConsoleDriverFacade<ConsoleKeyInfo>, IFakeDriverV2
{
internal FakeDriverV2 (
ConcurrentQueue<ConsoleKeyInfo> inputBuffer,
OutputBuffer outputBuffer,
FakeOutput fakeOutput,
Func<DateTime> datetimeFunc,
FakeSizeMonitor sizeMonitor
) :
base (
new NetInputProcessor (inputBuffer),
outputBuffer,
fakeOutput,
new (new AnsiResponseParser (), datetimeFunc),
sizeMonitor)
{
FakeOutput fakeOutput1;
InputBuffer = inputBuffer;
SizeMonitor = sizeMonitor;
OutputBuffer = outputBuffer;
ConsoleOutput = fakeOutput1 = fakeOutput;
SizeChanged += (_, e) =>
{
if (e.Size != null)
{
Size s = e.Size.Value;
fakeOutput1.Size = s;
OutputBuffer.SetWindowSize (s.Width, s.Height);
}
};
}
public void SetBufferSize (int width, int height)
{
SizeMonitor.RaiseSizeChanging (new (width, height));
OutputBuffer.SetWindowSize (width, height);
}
public IConsoleOutput ConsoleOutput { get; }
public ConcurrentQueue<ConsoleKeyInfo> InputBuffer { get; }
public new OutputBuffer OutputBuffer { get; }
public FakeSizeMonitor SizeMonitor { get; }
}

View File

@@ -0,0 +1,20 @@
#nullable enable
using System.Drawing;
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591
public class FakeSizeMonitor : IWindowSizeMonitor
{
/// <inheritdoc/>
public event EventHandler<SizeChangedEventArgs>? SizeChanging;
/// <inheritdoc/>
public bool Poll () { return false; }
/// <summary>
/// Raises the <see cref="SizeChanging"/> event.
/// </summary>
/// <param name="newSize"></param>
public void RaiseSizeChanging (Size newSize) { SizeChanging?.Invoke (this, new (newSize)); }
}

View File

@@ -0,0 +1,8 @@
#nullable enable
namespace Terminal.Gui.Drivers;
#pragma warning disable CS1591
public interface IFakeDriverV2 : IConsoleDriver, IConsoleDriverFacade
{
void SetBufferSize (int width, int height);
}

View File

@@ -1,159 +0,0 @@
using System.Collections.Concurrent;
using System.Drawing;
using TerminalGuiFluentTesting;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Terminal.Gui.Drivers;
public class FakeApplicationFactory
{
/// <summary>
/// Creates an initialized fake application which will be cleaned up when result object
/// is disposed.
/// </summary>
/// <returns></returns>
public IDisposable SetupFakeApplication ()
{
var cts = new CancellationTokenSource ();
var fakeInput = new FakeNetInput (cts.Token);
FakeOutput output = new ();
output.Size = new (25, 25);
IApplication origApp = ApplicationImpl.Instance;
var sizeMonitor = new FakeSizeMonitor ();
var v2 = new ApplicationV2 (new FakeNetComponentFactory (fakeInput, output, sizeMonitor));
ApplicationImpl.ChangeInstance (v2);
v2.Init (null,"v2net");
var d = (ConsoleDriverFacade<ConsoleKeyInfo>)Application.Driver!;
sizeMonitor.SizeChanging += (_, e) =>
{
if (e.Size != null)
{
var s = e.Size.Value;
output.Size = s;
d.OutputBuffer.SetWindowSize (s.Width, s.Height);
}
};
return new FakeApplicationLifecycle (origApp,cts);
}
}
class FakeApplicationLifecycle : IDisposable
{
private readonly IApplication _origApp;
private readonly CancellationTokenSource _hardStop;
public FakeApplicationLifecycle (IApplication origApp, CancellationTokenSource hardStop)
{
_origApp = origApp;
_hardStop = hardStop;
}
/// <inheritdoc />
public void Dispose ()
{
_hardStop.Cancel();
Application.Top?.Dispose ();
Application.Shutdown ();
ApplicationImpl.ChangeInstance (_origApp);
}
}
public class FakeDriverFactory
{
/// <summary>
/// Creates a new instance of <see cref="FakeDriverV2"/> using default options
/// </summary>
/// <returns></returns>
public IFakeDriverV2 Create ()
{
return new FakeDriverV2 (
new ConcurrentQueue<ConsoleKeyInfo> (),
new OutputBuffer (),
new FakeOutput (),
() => DateTime.Now,
new FakeSizeMonitor ());
}
}
public interface IFakeDriverV2 : IConsoleDriver, IConsoleDriverFacade
{
void SetBufferSize (int width, int height);
}
/// <summary>
/// Implementation of <see cref="IConsoleDriver"/> that uses fake input/output.
/// This is a lightweight alternative to <see cref="GuiTestContext"/> (if you don't
/// need the entire application main loop running).
/// </summary>
class FakeDriverV2 : ConsoleDriverFacade<ConsoleKeyInfo>, IFakeDriverV2
{
public ConcurrentQueue<ConsoleKeyInfo> InputBuffer { get; }
public FakeSizeMonitor SizeMonitor { get; }
public new OutputBuffer OutputBuffer { get; }
public IConsoleOutput ConsoleOutput { get; }
private FakeOutput _fakeOutput;
internal FakeDriverV2 (
ConcurrentQueue<ConsoleKeyInfo> inputBuffer,
OutputBuffer outputBuffer,
FakeOutput fakeOutput,
Func<DateTime> datetimeFunc,
FakeSizeMonitor sizeMonitor) :
base (new NetInputProcessor (inputBuffer),
outputBuffer,
fakeOutput,
new (new AnsiResponseParser (), datetimeFunc),
sizeMonitor)
{
InputBuffer = inputBuffer;
SizeMonitor = sizeMonitor;
OutputBuffer = outputBuffer;
ConsoleOutput = _fakeOutput = fakeOutput;
SizeChanged += (_, e) =>
{
if (e.Size != null)
{
var s = e.Size.Value;
_fakeOutput.Size = s;
OutputBuffer.SetWindowSize (s.Width,s.Height);
}
};
}
public void SetBufferSize (int width, int height)
{
SizeMonitor.RaiseSizeChanging (new Size (width,height));
OutputBuffer.SetWindowSize (width,height);
}
}
public class FakeSizeMonitor : IWindowSizeMonitor
{
/// <inheritdoc />
public event EventHandler<SizeChangedEventArgs>? SizeChanging;
/// <inheritdoc />
public bool Poll ()
{
return false;
}
/// <summary>
/// Raises the <see cref="SizeChanging"/> event.
/// </summary>
/// <param name="newSize"></param>
public void RaiseSizeChanging (Size newSize)
{
SizeChanging?.Invoke (this,new (newSize));
}
}

View File

@@ -4,7 +4,7 @@ namespace TerminalGuiFluentTesting;
internal class FakeOutput : IConsoleOutput internal class FakeOutput : IConsoleOutput
{ {
public IOutputBuffer LastBuffer { get; set; } public IOutputBuffer? LastBuffer { get; set; }
public Size Size { get; set; } public Size Size { get; set; }
/// <inheritdoc/> /// <inheritdoc/>