mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
This commit is contained in:
@@ -3,7 +3,9 @@ using TerminalGuiFluentTesting;
|
||||
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
/// <summary>
|
||||
/// Provides methods to create and manage a fake application for testing purposes.
|
||||
/// </summary>
|
||||
public class FakeApplicationFactory
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,35 +15,23 @@ public class FakeApplicationFactory
|
||||
/// <returns></returns>
|
||||
public IDisposable SetupFakeApplication ()
|
||||
{
|
||||
var cts = new CancellationTokenSource ();
|
||||
var fakeInput = new FakeNetInput (cts.Token);
|
||||
CancellationTokenSource hardStopTokenSource = new CancellationTokenSource ();
|
||||
FakeInput fakeInput = new FakeInput ();
|
||||
fakeInput.ExternalCancellationTokenSource = hardStopTokenSource;
|
||||
FakeOutput output = new ();
|
||||
output.Size = new (80, 25);
|
||||
output.SetSize (80, 25);
|
||||
|
||||
IApplication origApp = ApplicationImpl.Instance;
|
||||
|
||||
var sizeMonitor = new FakeSizeMonitor (output, output.LastBuffer!);
|
||||
SizeMonitorImpl sizeMonitor = new (output);
|
||||
|
||||
var impl = new ApplicationImpl (new FakeNetComponentFactory (fakeInput, output, sizeMonitor));
|
||||
ApplicationImpl impl = new (new FakeComponentFactory (fakeInput, output, sizeMonitor));
|
||||
|
||||
ApplicationImpl.ChangeInstance (impl);
|
||||
|
||||
// Initialize with a fake driver
|
||||
impl.Init (null, "fake");
|
||||
|
||||
// Handle different facade types - cast to common interface instead
|
||||
var d = (IConsoleDriverFacade)Application.Driver!;
|
||||
|
||||
sizeMonitor.SizeChanged += (_, e) =>
|
||||
{
|
||||
if (e.Size != null)
|
||||
{
|
||||
Size s = e.Size.Value;
|
||||
output.Size = s;
|
||||
d.OutputBuffer.SetSize (s.Width, s.Height);
|
||||
}
|
||||
};
|
||||
|
||||
return new FakeApplicationLifecycle (origApp, cts);
|
||||
return new FakeApplicationLifecycle (origApp, hardStopTokenSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#nullable enable
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
/// <summary>
|
||||
/// Implements a fake application lifecycle for testing purposes. Cleans up the application on dispose by cancelling
|
||||
/// the provided <see cref="CancellationTokenSource"/> and shutting down the application.
|
||||
/// </summary>
|
||||
/// <param name="origApp"></param>
|
||||
/// <param name="hardStop"></param>
|
||||
internal class FakeApplicationLifecycle (IApplication origApp, CancellationTokenSource hardStop) : IDisposable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
internal class FakeInput<T> : IConsoleInput<T>
|
||||
{
|
||||
private readonly CancellationToken _hardStopToken;
|
||||
|
||||
private readonly CancellationTokenSource _timeoutCts;
|
||||
|
||||
public FakeInput (CancellationToken hardStopToken)
|
||||
{
|
||||
_hardStopToken = hardStopToken;
|
||||
|
||||
// Create a timeout-based cancellation token too to prevent tests ever fully hanging
|
||||
_timeoutCts = new (With.Timeout);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose () { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize (ConcurrentQueue<T> inputBuffer) { InputBuffer = inputBuffer; }
|
||||
|
||||
public ConcurrentQueue<T>? InputBuffer { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Run (CancellationToken token)
|
||||
{
|
||||
// Blocks until either the token or the hardStopToken is cancelled.
|
||||
WaitHandle.WaitAny ([token.WaitHandle, _hardStopToken.WaitHandle, _timeoutCts.Token.WaitHandle]);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
internal class FakeNetInput (CancellationToken hardStopToken) : FakeInput<ConsoleKeyInfo> (hardStopToken), INetInput
|
||||
{ }
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
internal class FakeOutput : IConsoleOutput
|
||||
{
|
||||
public IOutputBuffer? LastBuffer { get; set; }
|
||||
public Size Size { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose () { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Write (ReadOnlySpan<char> text) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Write (IOutputBuffer buffer) { LastBuffer = buffer; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Size GetSize () { return Size; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetCursorVisibility (CursorVisibility visibility) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetCursorPosition (int col, int row) { CursorPosition = new Point (col, row); }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetSize (int width, int height)
|
||||
{
|
||||
Size = new (width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The last value set by calling <see cref="SetCursorPosition"/>
|
||||
/// </summary>
|
||||
public Point CursorPosition { get; private set; }
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Drawing;
|
||||
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
public class FakeSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer _) : IConsoleSizeMonitor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<SizeChangedEventArgs>? SizeChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Poll () { return false; }
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="SizeChanged"/> event.
|
||||
/// </summary>
|
||||
/// <param name="newSize"></param>
|
||||
public void RaiseSizeChanged (Size newSize) { SizeChanged?.Invoke (this, new (newSize)); }
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
internal class FakeWindowsInput (CancellationToken hardStopToken) : FakeInput<WindowsConsole.InputRecord> (hardStopToken), IWindowsInput
|
||||
{ }
|
||||
28
Tests/TerminalGuiFluentTesting/GuiTestContext.ContextMenu.cs
Normal file
28
Tests/TerminalGuiFluentTesting/GuiTestContext.ContextMenu.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
public partial class GuiTestContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a right click handler on the <see cref="LastView"/> added view (or root view) that
|
||||
/// will open the supplied <paramref name="contextMenu"/>.
|
||||
/// </summary>
|
||||
/// <param name="contextMenu"></param>
|
||||
/// <returns></returns>
|
||||
public GuiTestContext WithContextMenu (PopoverMenu? contextMenu)
|
||||
{
|
||||
LastView.MouseEvent += (s, e) =>
|
||||
{
|
||||
if (e.Flags.HasFlag (MouseFlags.Button3Clicked))
|
||||
{
|
||||
// Registering with the PopoverManager will ensure that the context menu is closed when the view is no longer focused
|
||||
// and the context menu is disposed when it is closed.
|
||||
Application.Popover?.Register (contextMenu);
|
||||
contextMenu?.MakeVisible (e.ScreenPosition);
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
223
Tests/TerminalGuiFluentTesting/GuiTestContext.Input.cs
Normal file
223
Tests/TerminalGuiFluentTesting/GuiTestContext.Input.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System.Drawing;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
public partial class GuiTestContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Simulates a right click at the given screen coordinates on the current driver.
|
||||
/// This is a raw input event that goes through entire processing pipeline as though
|
||||
/// user had pressed the mouse button physically.
|
||||
/// </summary>
|
||||
/// <param name="screenX">0 indexed screen coordinates</param>
|
||||
/// <param name="screenY">0 indexed screen coordinates</param>
|
||||
/// <returns></returns>
|
||||
public GuiTestContext RightClick (int screenX, int screenY)
|
||||
{
|
||||
return EnqueueMouseEvent (new ()
|
||||
{
|
||||
Flags = MouseFlags.Button3Clicked,
|
||||
ScreenPosition = new (screenX, screenY)
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates a left click at the given screen coordinates on the current driver.
|
||||
/// This is a raw input event that goes through entire processing pipeline as though
|
||||
/// user had pressed the mouse button physically.
|
||||
/// </summary>
|
||||
/// <param name="screenX">0 indexed screen coordinates</param>
|
||||
/// <param name="screenY">0 indexed screen coordinates</param>
|
||||
/// <returns></returns>
|
||||
public GuiTestContext LeftClick (int screenX, int screenY)
|
||||
{
|
||||
return EnqueueMouseEvent (new ()
|
||||
{
|
||||
Flags = MouseFlags.Button1Clicked,
|
||||
ScreenPosition = new (screenX, screenY),
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates a left mouse click on the top-left cell of the Viewport of the View of type TView determined by the
|
||||
/// <paramref name="evaluator"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TView"></typeparam>
|
||||
/// <param name="evaluator"></param>
|
||||
/// <returns></returns>
|
||||
public GuiTestContext LeftClick<TView> (Func<TView, bool> evaluator) where TView : View
|
||||
{
|
||||
return EnqueueMouseEvent (new ()
|
||||
{
|
||||
Flags = MouseFlags.Button1Clicked,
|
||||
}, evaluator);
|
||||
}
|
||||
|
||||
private GuiTestContext EnqueueMouseEvent (MouseEventArgs mouseEvent)
|
||||
{
|
||||
// Enqueue the mouse event
|
||||
WaitIteration (() =>
|
||||
{
|
||||
if (Application.Driver is { })
|
||||
{
|
||||
mouseEvent.Position = mouseEvent.ScreenPosition;
|
||||
|
||||
Application.Driver.InputProcessor.EnqueueMouseEvent (mouseEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fail ("Expected Application.Driver to be non-null.");
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the event to be processed (similar to EnqueueKeyEvent)
|
||||
return WaitIteration ();
|
||||
}
|
||||
|
||||
|
||||
private GuiTestContext EnqueueMouseEvent<TView> (MouseEventArgs mouseEvent, Func<TView, bool> evaluator) where TView : View
|
||||
{
|
||||
var screen = Point.Empty;
|
||||
|
||||
GuiTestContext ctx = WaitIteration (() =>
|
||||
{
|
||||
TView v = Find (evaluator);
|
||||
screen = v.ViewportToScreen (new Point (0, 0));
|
||||
});
|
||||
mouseEvent.ScreenPosition = screen;
|
||||
mouseEvent.Position = new Point (0, 0);
|
||||
|
||||
EnqueueMouseEvent (mouseEvent);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
//private GuiTestContext Click (WindowsConsole.ButtonState btn, int screenX, int screenY)
|
||||
//{
|
||||
// switch (_driverType)
|
||||
// {
|
||||
// case TestDriver.Windows:
|
||||
|
||||
// _winInput!.InputQueue!.Enqueue (
|
||||
// new ()
|
||||
// {
|
||||
// EventType = WindowsConsole.EventType.Mouse,
|
||||
// MouseEvent = new ()
|
||||
// {
|
||||
// ButtonState = btn,
|
||||
// MousePosition = new ((short)screenX, (short)screenY)
|
||||
// }
|
||||
// });
|
||||
|
||||
// _winInput.InputQueue.Enqueue (
|
||||
// new ()
|
||||
// {
|
||||
// EventType = WindowsConsole.EventType.Mouse,
|
||||
// MouseEvent = new ()
|
||||
// {
|
||||
// ButtonState = WindowsConsole.ButtonState.NoButtonPressed,
|
||||
// MousePosition = new ((short)screenX, (short)screenY)
|
||||
// }
|
||||
// });
|
||||
|
||||
// return WaitUntil (() => _winInput.InputQueue.IsEmpty);
|
||||
|
||||
// case TestDriver.DotNet:
|
||||
|
||||
// int netButton = btn switch
|
||||
// {
|
||||
// WindowsConsole.ButtonState.Button1Pressed => 0,
|
||||
// WindowsConsole.ButtonState.Button2Pressed => 1,
|
||||
// WindowsConsole.ButtonState.Button3Pressed => 2,
|
||||
// WindowsConsole.ButtonState.RightmostButtonPressed => 2,
|
||||
// _ => throw new ArgumentOutOfRangeException (nameof (btn))
|
||||
// };
|
||||
|
||||
// foreach (ConsoleKeyInfo k in NetSequences.Click (netButton, screenX, screenY))
|
||||
// {
|
||||
// SendNetKey (k, false);
|
||||
// }
|
||||
|
||||
// return WaitIteration ();
|
||||
|
||||
// case TestDriver.Unix:
|
||||
|
||||
// int unixButton = btn switch
|
||||
// {
|
||||
// WindowsConsole.ButtonState.Button1Pressed => 0,
|
||||
// WindowsConsole.ButtonState.Button2Pressed => 1,
|
||||
// WindowsConsole.ButtonState.Button3Pressed => 2,
|
||||
// WindowsConsole.ButtonState.RightmostButtonPressed => 2,
|
||||
// _ => throw new ArgumentOutOfRangeException (nameof (btn))
|
||||
// };
|
||||
|
||||
// foreach (ConsoleKeyInfo k in NetSequences.Click (unixButton, screenX, screenY))
|
||||
// {
|
||||
// SendUnixKey (k.KeyChar, false);
|
||||
// }
|
||||
|
||||
// return WaitIteration ();
|
||||
|
||||
// case TestDriver.Fake:
|
||||
|
||||
// int fakeButton = btn switch
|
||||
// {
|
||||
// WindowsConsole.ButtonState.Button1Pressed => 0,
|
||||
// WindowsConsole.ButtonState.Button2Pressed => 1,
|
||||
// WindowsConsole.ButtonState.Button3Pressed => 2,
|
||||
// WindowsConsole.ButtonState.RightmostButtonPressed => 2,
|
||||
// _ => throw new ArgumentOutOfRangeException (nameof (btn))
|
||||
// };
|
||||
|
||||
// foreach (ConsoleKeyInfo k in NetSequences.Click (fakeButton, screenX, screenY))
|
||||
// {
|
||||
// SendFakeKey (k, false);
|
||||
// }
|
||||
|
||||
// return WaitIteration ();
|
||||
|
||||
// default:
|
||||
// throw new ArgumentOutOfRangeException ();
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a key down event to the current driver's input processor.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// Enqueues a key down event to the current driver's input processor.
|
||||
/// </summary>
|
||||
public GuiTestContext EnqueueKeyEvent (Key key)
|
||||
{
|
||||
//Logging.Trace ($"Enqueuing key: {key}");
|
||||
|
||||
// Enqueue the key event and wait for it to be processed.
|
||||
// We do this by subscribing to the Driver.KeyDown event and waiting until it is raised.
|
||||
// This prevents the application from missing the key event if we enqueue it and immediately return.
|
||||
bool keyReceived = false;
|
||||
if (_applicationImpl?.Driver is { })
|
||||
{
|
||||
_applicationImpl.Driver.KeyDown += DriverOnKeyDown;
|
||||
_applicationImpl.Driver.EnqueueKeyEvent (key);
|
||||
WaitUntil (() => keyReceived);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fail ("Expected Application.Driver to be non-null.");
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
|
||||
void DriverOnKeyDown (object? sender, Key e)
|
||||
{
|
||||
_applicationImpl.Driver.KeyDown -= DriverOnKeyDown;
|
||||
keyReceived = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
94
Tests/TerminalGuiFluentTesting/GuiTestContext.Navigation.cs
Normal file
94
Tests/TerminalGuiFluentTesting/GuiTestContext.Navigation.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
public partial class GuiTestContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the input focus to the given <see cref="View"/>.
|
||||
/// Throws <see cref="ArgumentException"/> if focus did not change due to system
|
||||
/// constraints e.g. <paramref name="toFocus"/>
|
||||
/// <see cref="View.CanFocus"/> is <see langword="false"/>
|
||||
/// </summary>
|
||||
/// <param name="toFocus"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public GuiTestContext Focus (View toFocus)
|
||||
{
|
||||
toFocus.FocusDeepest (NavigationDirection.Forward, TabBehavior.TabStop);
|
||||
|
||||
if (!toFocus.HasFocus)
|
||||
{
|
||||
throw new ArgumentException ("Failed to set focus, FocusDeepest did not result in HasFocus becoming true. Ensure view is added and focusable");
|
||||
}
|
||||
|
||||
return WaitIteration ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tabs through the UI until a View matching the <paramref name="evaluator"/>
|
||||
/// is found (of Type T) or all views are looped through (back to the beginning)
|
||||
/// in which case triggers hard stop and Exception
|
||||
/// </summary>
|
||||
/// <param name="evaluator">
|
||||
/// Delegate that returns true if the passed View is the one
|
||||
/// you are trying to focus. Leave <see langword="null"/> to focus the first view of type
|
||||
/// <typeparamref name="T"/>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public GuiTestContext Focus<T> (Func<T, bool>? evaluator = null) where T : View
|
||||
{
|
||||
evaluator ??= _ => true;
|
||||
Toplevel? t = Application.Top;
|
||||
|
||||
HashSet<View> seen = new ();
|
||||
|
||||
if (t == null)
|
||||
{
|
||||
Fail ("Application.Top was null when trying to set focus");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
View? next = t.MostFocused;
|
||||
|
||||
// Is view found?
|
||||
if (next is T v && evaluator (v))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// No, try tab to the next (or first)
|
||||
EnqueueKeyEvent (Application.NextTabKey);
|
||||
WaitIteration ();
|
||||
|
||||
next = t.MostFocused;
|
||||
|
||||
if (next is null)
|
||||
{
|
||||
Fail (
|
||||
"Failed to tab to a view which matched the Type and evaluator constraints of the test because MostFocused became or was always null"
|
||||
+ DescribeSeenViews (seen));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Track the views we have seen
|
||||
// We have looped around to the start again if it was already there
|
||||
if (!seen.Add (next))
|
||||
{
|
||||
Fail (
|
||||
"Failed to tab to a view which matched the Type and evaluator constraints of the test before looping back to the original View"
|
||||
+ DescribeSeenViews (seen));
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
private string DescribeSeenViews (HashSet<View> seen) { return Environment.NewLine + string.Join (Environment.NewLine, seen); }
|
||||
}
|
||||
72
Tests/TerminalGuiFluentTesting/GuiTestContext.ViewBase.cs
Normal file
72
Tests/TerminalGuiFluentTesting/GuiTestContext.ViewBase.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
public partial class GuiTestContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the given <paramref name="v"/> to the current top level view
|
||||
/// and performs layout.
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
/// <returns></returns>
|
||||
public GuiTestContext Add (View v)
|
||||
{
|
||||
WaitIteration (() =>
|
||||
{
|
||||
Toplevel top = Application.Top ?? throw new ("Top was null so could not add view");
|
||||
top.Add (v);
|
||||
top.Layout ();
|
||||
_lastView = v;
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private View? _lastView;
|
||||
|
||||
/// <summary>
|
||||
/// The last view added (e.g. with <see cref="Add"/>) or the root/current top.
|
||||
/// </summary>
|
||||
public View LastView => _lastView ?? Application.Top ?? throw new ("Could not determine which view to add to");
|
||||
|
||||
private T Find<T> (Func<T, bool> evaluator) where T : View
|
||||
{
|
||||
Toplevel? t = Application.Top;
|
||||
|
||||
if (t == null)
|
||||
{
|
||||
Fail ("Application.Top was null when attempting to find view");
|
||||
}
|
||||
|
||||
T? f = FindRecursive (t!, evaluator);
|
||||
|
||||
if (f == null)
|
||||
{
|
||||
Fail ("Failed to tab to a view which matched the Type and evaluator constraints in any SubViews of top");
|
||||
}
|
||||
|
||||
return f!;
|
||||
}
|
||||
|
||||
private T? FindRecursive<T> (View current, Func<T, bool> evaluator) where T : View
|
||||
{
|
||||
foreach (View subview in current.SubViews)
|
||||
{
|
||||
if (subview is T match && evaluator (match))
|
||||
{
|
||||
return match;
|
||||
}
|
||||
|
||||
// Recursive call
|
||||
T? result = FindRecursive (subview, evaluator);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TerminalGuiFluentTesting;
|
||||
namespace TerminalGuiFluentTesting;
|
||||
|
||||
/// <summary>
|
||||
/// Which driver simulation should be used for testing
|
||||
/// Which driver simulation should be used for testing
|
||||
/// </summary>
|
||||
public enum TestDriver
|
||||
{
|
||||
/// <summary>
|
||||
/// The Windows driver with simulation I/O but core driver classes
|
||||
/// The Windows driver with simulation I/O but core driver classes
|
||||
/// </summary>
|
||||
Windows,
|
||||
|
||||
/// <summary>
|
||||
/// The DotNet driver with simulation I/O but core driver classes
|
||||
/// The DotNet driver with simulation I/O but core driver classes
|
||||
/// </summary>
|
||||
DotNet
|
||||
DotNet,
|
||||
|
||||
/// <summary>
|
||||
/// The Unix driver with simulation I/O but core driver classes
|
||||
/// </summary>
|
||||
Unix,
|
||||
|
||||
/// <summary>
|
||||
/// The Fake driver that does not use any core driver classes
|
||||
/// </summary>
|
||||
Fake
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ public static class With
|
||||
/// <param name="testDriver">Which v2 testDriver to use for the test</param>
|
||||
/// <param name="logWriter"></param>
|
||||
/// <returns></returns>
|
||||
public static GuiTestContext A<T> (int width, int height, TestDriver testDriver, TextWriter? logWriter = null) where T : Toplevel, new ()
|
||||
public static GuiTestContext A<T> (int width, int height, TestDriver testDriver, TextWriter? logWriter = null) where T : Toplevel, new()
|
||||
{
|
||||
return new (() => new T (), width, height, testDriver, logWriter, Timeout);
|
||||
return new (() => new T ()
|
||||
{
|
||||
//Id = $"{typeof (T).Name}"
|
||||
}, width, height, testDriver, logWriter, Timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,5 +39,5 @@ public static class With
|
||||
/// </summary>
|
||||
public static TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds (30);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user