mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Fixed MouseGrabView bug. Added extensive test coverage for `Keyboard`, `Mouse`, `Timeout`, and `Popover` functionalities, including edge cases and concurrent access. Introduced parameterized and data-driven tests to reduce redundancy and improve clarity. Refactored codebase for modularity and maintainability, introducing new namespaces and reorganizing classes. Enhanced `MouseImpl`, `KeyboardImpl`, and `Runnable` implementations with improved event handling, thread safety, and support for the Terminal.Gui Cancellable Work Pattern (CWP). Removed deprecated code and legacy tests, such as `LogarithmicTimeout` and `SmoothAcceleratingTimeout`. Fixed bugs related to mouse grabbing during drag operations and unbalanced `ApplicationImpl.Begin/End` calls. Improved documentation and code readability with modern C# features. * Code cleanup. * Update Tests/UnitTestsParallelizable/Application/Runnable/RunnableIntegrationTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Improve null handling and simplify test setup In `MouseImpl.cs`, added an early `return` after the `UngrabMouse()` call within the `if (view is null)` block to prevent further execution when `view` is `null`, improving null reference handling. In `RunnableIntegrationTests.cs`, removed the initialization of the `IApplication` object (`app`) from the `MultipleRunnables_IndependentResults` test method, simplifying the test setup and focusing on runnable behavior. * Code cleanup * API doc link cleanup --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
253 lines
6.7 KiB
C#
253 lines
6.7 KiB
C#
#nullable enable
|
|
using Xunit.Abstractions;
|
|
|
|
namespace ApplicationTests;
|
|
|
|
public class RunTests
|
|
{
|
|
[Fact]
|
|
public void Run_RequestStop_Stops ()
|
|
{
|
|
IApplication? app = Application.Create ();
|
|
app.Init ("fake");
|
|
|
|
var top = new Runnable ();
|
|
SessionToken? sessionToken = app.Begin (top);
|
|
Assert.NotNull (sessionToken);
|
|
|
|
app.Iteration += OnApplicationOnIteration;
|
|
app.Run (top);
|
|
app.Iteration -= OnApplicationOnIteration;
|
|
|
|
top.Dispose ();
|
|
|
|
return;
|
|
|
|
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a) { app.RequestStop (); }
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_Init_Driver_Cleared_with_Runnable_Throws ()
|
|
{
|
|
IApplication? app = Application.Create ();
|
|
|
|
app.Init ("fake");
|
|
app.Driver = null;
|
|
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
// Init has been called, but Driver has been set to null. Bad.
|
|
Assert.Throws<InvalidOperationException> (() => app.Run<Runnable> ());
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_Iteration_Fires ()
|
|
{
|
|
var iteration = 0;
|
|
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
|
|
app.Iteration += Application_Iteration;
|
|
app.Run<Runnable> ();
|
|
app.Iteration -= Application_Iteration;
|
|
|
|
Assert.Equal (1, iteration);
|
|
app.Dispose ();
|
|
|
|
return;
|
|
|
|
void Application_Iteration (object? sender, EventArgs<IApplication?> e)
|
|
{
|
|
|
|
iteration++;
|
|
app.RequestStop ();
|
|
}
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void Run_T_After_InitWithDriver_with_Runnable_and_Driver_Does_Not_Throw ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
// Run<Runnable<bool>> when already initialized or not with a Driver will not throw (because Window is derived from Runnable)
|
|
// Using another type not derived from Runnable will throws at compile time
|
|
app.Run<Window> (null, "fake");
|
|
|
|
// Run<Runnable<bool>> when already initialized or not with a Driver will not throw (because Dialog is derived from Runnable)
|
|
app.Run<Dialog> (null, "fake");
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_After_Init_Does_Not_Disposes_Application_Top ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
|
|
// Init doesn't create a Runnable and assigned it to app.TopRunnable
|
|
// but Begin does
|
|
var initTop = new Runnable ();
|
|
|
|
app.Iteration += OnApplicationOnIteration;
|
|
|
|
app.Run<Runnable> ();
|
|
app.Iteration -= OnApplicationOnIteration;
|
|
|
|
#if DEBUG_IDISPOSABLE
|
|
Assert.False (initTop.WasDisposed);
|
|
initTop.Dispose ();
|
|
Assert.True (initTop.WasDisposed);
|
|
#endif
|
|
initTop.Dispose ();
|
|
|
|
app.Dispose ();
|
|
|
|
return;
|
|
|
|
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
|
|
{
|
|
Assert.NotEqual (initTop, app.TopRunnableView);
|
|
#if DEBUG_IDISPOSABLE
|
|
Assert.False (initTop.WasDisposed);
|
|
#endif
|
|
app.RequestStop ();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_After_InitWithDriver_with_TestRunnable_DoesNotThrow ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
// Init has been called and we're passing no driver to Run<TestRunnable>. This is ok.
|
|
app.Run<Window> ();
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_After_InitNullDriver_with_TestRunnable_DoesNotThrow ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
// Init has been called, selecting FakeDriver; we're passing no driver to Run<TestRunnable>. Should be fine.
|
|
app.Run<Window> ();
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_NoInit_DoesNotThrow ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
app.Run<Window> ();
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_NoInit_WithDriver_DoesNotThrow ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
// Init has NOT been called and we're passing a valid driver to Run<TestRunnable>. This is ok.
|
|
app.Run<Runnable> (null, "fake");
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_Sets_Running_True ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
|
|
var top = new Runnable ();
|
|
SessionToken? rs = app.Begin (top);
|
|
Assert.NotNull (rs);
|
|
|
|
app.Iteration += OnApplicationOnIteration;
|
|
app.Run (top);
|
|
app.Iteration -= OnApplicationOnIteration;
|
|
|
|
top.Dispose ();
|
|
|
|
app.Dispose ();
|
|
|
|
return;
|
|
|
|
void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
|
|
{
|
|
Assert.True (top.IsRunning);
|
|
top.RequestStop ();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_A_Modal_Runnable_Refresh_Background_On_Moving ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.Init ("fake");
|
|
|
|
// Don't use Dialog here as it has more layout logic. Use Window instead.
|
|
var w = new Window
|
|
{
|
|
Width = 5, Height = 5,
|
|
Arrangement = ViewArrangement.Movable
|
|
};
|
|
app.Driver!.SetScreenSize (10, 10);
|
|
SessionToken? rs = app.Begin (w);
|
|
|
|
// Don't use visuals to test as style of border can change over time.
|
|
Assert.Equal (new (0, 0), w.Frame.Location);
|
|
|
|
app.Mouse.RaiseMouseEvent (new () { Flags = MouseFlags.Button1Pressed });
|
|
Assert.Equal (w.Border, app.Mouse.MouseGrabView);
|
|
Assert.Equal (new (0, 0), w.Frame.Location);
|
|
|
|
// Move down and to the right.
|
|
app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (1, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
|
|
Assert.Equal (new (1, 1), w.Frame.Location);
|
|
|
|
app.End (rs!);
|
|
w.Dispose ();
|
|
|
|
app.Dispose ();
|
|
}
|
|
|
|
[Fact]
|
|
public void Run_T_Creates_Top_Without_Init ()
|
|
{
|
|
IApplication app = Application.Create ();
|
|
app.StopAfterFirstIteration = true;
|
|
|
|
app.SessionEnded += OnApplicationOnSessionEnded;
|
|
|
|
app.Run<Window> (null, "fake");
|
|
|
|
Assert.Null (app.TopRunnableView);
|
|
|
|
app.Dispose ();
|
|
Assert.Null (app.TopRunnableView);
|
|
|
|
return;
|
|
|
|
void OnApplicationOnSessionEnded (object? sender, SessionTokenEventArgs e)
|
|
{
|
|
app.SessionEnded -= OnApplicationOnSessionEnded;
|
|
e.State.Result = (e.State.Runnable as IRunnable<object?>)?.Result;
|
|
}
|
|
}
|
|
}
|