Fixed all modelusage bugs?

Replaced static `Application` references with instance-based `App`
context across the codebase. Updated calls to `Application.RequestStop()`
and `Application.Screen` to use `App?.RequestStop()` and `App?.Screen`
for better encapsulation and flexibility.

Refactored test infrastructure to align with the new context, including
reintroducing `FakeApplicationFactory` and `FakeApplicationLifecycle`
for testing purposes. Improved logging, error handling, and test
clarity by adding `logWriter` support and simplifying test setup.

Removed redundant or obsolete code, such as `NetSequences` and the old
`FakeApplicationFactory` implementation. Updated documentation to
reflect the new `IApplication.RequestStop()` usage.
This commit is contained in:
Tig
2025-11-23 07:13:47 -07:00
parent ad6925a13a
commit bc0634cf44
18 changed files with 75 additions and 119 deletions

View File

@@ -266,7 +266,7 @@ public class Dialogs : Scenario
{
Title = titleEdit.Text,
Text = "Dialog Text",
ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [(int)alignmentGroup.Value!.Value] [1..]),
ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [(int)alignmentGroup.Value!.Value] [0..]),
Buttons = buttons.ToArray ()
};

View File

@@ -200,7 +200,7 @@ public class DynamicStatusBar : Scenario
TextTitle.Text = string.Empty;
Application.RequestStop ();
};
var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, Application.Screen.Height) };
var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, App?.Screen.Height) };
Width = Dim.Fill ();
Height = Dim.Fill () - 2;

View File

@@ -37,7 +37,7 @@ public partial class ColorPicker
{
accept = true;
e.Handled = true;
Application.RequestStop ();
(s as View)?.App?.RequestStop ();
};
var btnCancel = new Button
@@ -51,7 +51,7 @@ public partial class ColorPicker
btnCancel.Accepting += (s, e) =>
{
e.Handled = true;
Application.RequestStop ();
(s as View)?.App ?.RequestStop ();
};
d.Add (btnOk);

View File

@@ -11,7 +11,7 @@ namespace Terminal.Gui.Views;
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>. This will execute the dialog until
/// it terminates via the <see cref="Application.QuitKey"/> (`Esc` by default),
/// or when one of the views or buttons added to the dialog calls
/// <see cref="Application.RequestStop"/>.
/// <see cref="IApplication.RequestStop()"/>.
/// </remarks>
public class Dialog : Window
{

View File

@@ -138,7 +138,7 @@ public class DefaultFileOperations : IFileOperations
btnOk.Accepting += (s, e) =>
{
confirm = true;
Application.RequestStop ();
(s as View)?.App?.RequestStop ();
// When Accepting is handled, set e.Handled to true to prevent further processing.
e.Handled = true;
};
@@ -147,7 +147,7 @@ public class DefaultFileOperations : IFileOperations
btnCancel.Accepting += (s, e) =>
{
confirm = false;
Application.RequestStop ();
(s as View)?.App?.RequestStop ();
// When Accepting is handled, set e.Handled to true to prevent further processing.
e.Handled = true;
};

View File

@@ -108,7 +108,7 @@ public class FileDialog : Dialog, IDesignable
if (Modal)
{
Application.RequestStop ();
(s as View)?.App?.RequestStop ();
}
};
@@ -468,7 +468,6 @@ public class FileDialog : Dialog, IDesignable
Style.IconProvider.IsOpenGetter = _treeView.IsExpanded;
_treeView.AddObjects (_treeRoots.Keys);
#if MENU_V1
// if filtering on file type is configured then create the ComboBox and establish
// initial filtering by extension(s)
@@ -479,6 +478,7 @@ public class FileDialog : Dialog, IDesignable
// Fiddle factor
int width = AllowedTypes.Max (a => a.ToString ()!.Length) + 6;
#if MENU_V1
_allowedTypeMenu = new (
"<placeholder>",
_allowedTypeMenuItems = AllowedTypes.Select (
@@ -512,8 +512,8 @@ public class FileDialog : Dialog, IDesignable
};
Add (_allowedTypeMenuBar);
}
#endif
}
// if no path has been provided
if (_tbPath.Text.Length <= 0)
@@ -879,7 +879,7 @@ public class FileDialog : Dialog, IDesignable
if (Modal)
{
Application.RequestStop ();
App?.RequestStop ();
}
}

View File

@@ -360,7 +360,7 @@ public static class MessageBox
if (count == defaultButton)
{
b.IsDefault = true;
b.Accepting += (_, e) =>
b.Accepting += (s, e) =>
{
if (e?.Context?.Source is Button button)
{
@@ -376,7 +376,7 @@ public static class MessageBox
e.Handled = true;
}
Application.RequestStop ();
(s as View)?.App?.RequestStop ();
};
}

View File

@@ -1534,7 +1534,7 @@ public class TableView : View, IDesignable
/// <param name="width"></param>
private void ClearLine (int row, int width)
{
if (Application.Screen.Height == 0)
if (App?.Screen.Height == 0)
{
return;
}
@@ -1810,7 +1810,7 @@ public class TableView : View, IDesignable
}
}
if (Application.Screen.Height > 0)
if (App?.Screen.Height > 0)
{
AddRuneAt (c, row, rune);
}

View File

@@ -458,7 +458,7 @@ public class Wizard : Dialog
if (IsCurrentTop)
{
Application.RequestStop (this);
(sender as View)?.App?.RequestStop (this);
e.Handled = true;
}

View File

@@ -60,10 +60,10 @@ public class FileDialogFluentTests
public void CancelFileDialog_QuitKey_Quits (TestDriver d)
{
SaveDialog? sd = null;
using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d)
.ScreenShot ("Save dialog", _out)
.EnqueueKeyEvent (Application.QuitKey)
.AssertTrue (sd!.Canceled);
using GuiTestContext c = With.A (() => NewSaveDialog (out sd), 100, 20, d, logWriter: _out)
.ScreenShot ("Save dialog", _out)
.EnqueueKeyEvent (Application.QuitKey)
.AssertTrue (sd!.Canceled);
}
[Theory]
@@ -93,7 +93,7 @@ public class FileDialogFluentTests
public void CancelFileDialog_UsingCancelButton_AltC (TestDriver d)
{
SaveDialog? sd = null;
using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d)
using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d, _out)
.ScreenShot ("Save dialog", _out)
.EnqueueKeyEvent (Key.C.WithAlt)
.AssertTrue (sd!.Canceled);
@@ -132,12 +132,13 @@ public class FileDialogFluentTests
{
SaveDialog? sd = null;
MockFileSystem? fs = null;
using var c = With.A (() => NewSaveDialog (out sd, out fs, modal: false), 100, 20, d)
.ScreenShot ("Save dialog", _out)
.Focus<Button> (b => b.Text == "_Save")
.EnqueueKeyEvent (Key.Enter)
.AssertFalse (sd!.Canceled)
.AssertEqual (GetFileSystemRoot (fs!), sd!.FileName);
using GuiTestContext c = With.A (() => NewSaveDialog (out sd, out fs, modal: false), 100, 20, d)
.ScreenShot ("Save dialog", _out)
.Focus<Button> (b => b.Text == "_Save")
.EnqueueKeyEvent (Key.Enter)
.AssertFalse (sd!.Canceled)
.AssertEqual (GetFileSystemRoot (fs!), sd!.FileName)
;
}
private string GetFileSystemRoot (IFileSystem fs)

View File

@@ -18,7 +18,7 @@ public class GuiTestContextTests (ITestOutputHelper outputHelper)
{
using var context = new GuiTestContext (d, _out, TimeSpan.FromSeconds (10));
Assert.NotEqual (Rectangle.Empty, Application.Screen);
Assert.NotEqual (Rectangle.Empty, context.App?.Screen);
}
[Theory]

View File

@@ -205,11 +205,6 @@ public partial class GuiTestContext
App.Driver.EnqueueKeyEvent (key);
WaitUntil (() => keyReceived);
}
else
{
Fail ("Expected Application.Driver to be non-null.");
}
return this;

View File

@@ -68,7 +68,7 @@ public partial class GuiTestContext : IDisposable
try
{
InitializeApplication ();
App?.Init (GetDriverName ());
_booting.Release ();
// After Init, Application.Screen should be set by the driver
@@ -119,21 +119,36 @@ public partial class GuiTestContext : IDisposable
{
try
{
InitializeApplication ();
try
{
App?.Init (GetDriverName ());
}
catch (Exception e)
{
Logging.Error(e.Message);
_runCancellationTokenSource.Cancel ();
}
finally
{
_booting.Release ();
}
_booting.Release ();
if (App is { Initialized: true })
{
Toplevel t = topLevelBuilder ();
t.Closed += (s, e) => { Finished = true; };
App?.Run (t); // This will block, but it's on a background thread now
Toplevel t = topLevelBuilder ();
t.Closed += (s, e) => { Finished = true; };
App?.Run (t); // This will block, but it's on a background thread now
t.Dispose ();
Logging.Trace ("Application.Run completed");
App?.Shutdown ();
_runCancellationTokenSource.Cancel ();
t.Dispose ();
Logging.Trace ("Application.Run completed");
App?.Shutdown ();
_runCancellationTokenSource.Cancel ();
}
}
catch (OperationCanceledException)
{ }
{
Logging.Trace ("OperationCanceledException");
}
catch (Exception ex)
{
_backgroundException = ex;
@@ -142,7 +157,6 @@ public partial class GuiTestContext : IDisposable
finally
{
CleanupApplication ();
if (_logWriter != null)
{
WriteOutLogs (_logWriter);
@@ -165,11 +179,6 @@ public partial class GuiTestContext : IDisposable
}
}
private void InitializeApplication ()
{
App?.Init (GetDriverName ());
}
/// <summary>
/// Common initialization for both constructors.
@@ -316,7 +325,7 @@ public partial class GuiTestContext : IDisposable
throw new NotSupportedException ("Cannot WaitIteration during Invoke");
}
Logging.Trace ($"WaitIteration started");
//Logging.Trace ($"WaitIteration started");
if (action is null)
{
action = (app) => { };
@@ -358,8 +367,9 @@ public partial class GuiTestContext : IDisposable
GuiTestContext? c = null;
var sw = Stopwatch.StartNew ();
//Logging.Trace ($"WaitUntil started with timeout {_timeout}");
Logging.Trace ($"WaitUntil started with timeout {_timeout}");
int count = 0;
while (!condition ())
{
if (sw.Elapsed > _timeout)
@@ -368,8 +378,10 @@ public partial class GuiTestContext : IDisposable
}
c = WaitIteration ();
count++;
}
Logging.Trace ($"WaitUntil completed after {sw.ElapsedMilliseconds}ms and {count} iterations");
return c ?? this;
}

View File

@@ -1,53 +0,0 @@
namespace TerminalGuiFluentTesting;
class NetSequences
{
public static ConsoleKeyInfo [] Down = new []
{
new ConsoleKeyInfo('\x1B', ConsoleKey.Enter, false, false, false),
new ConsoleKeyInfo('[', ConsoleKey.None, false, false, false),
new ConsoleKeyInfo('B', ConsoleKey.None, false, false, false),
};
public static ConsoleKeyInfo [] Up = new []
{
new ConsoleKeyInfo('\x1B', ConsoleKey.Enter, false, false, false),
new ConsoleKeyInfo('[', ConsoleKey.None, false, false, false),
new ConsoleKeyInfo('A', ConsoleKey.None, false, false, false),
};
public static ConsoleKeyInfo [] Left = new []
{
new ConsoleKeyInfo('\x1B', ConsoleKey.Enter, false, false, false),
new ConsoleKeyInfo('[', ConsoleKey.None, false, false, false),
new ConsoleKeyInfo('D', ConsoleKey.None, false, false, false),
};
public static ConsoleKeyInfo [] Right = new []
{
new ConsoleKeyInfo('\x1B', ConsoleKey.Enter, false, false, false),
new ConsoleKeyInfo('[', ConsoleKey.None, false, false, false),
new ConsoleKeyInfo('C', ConsoleKey.None, false, false, false),
};
public static IEnumerable<ConsoleKeyInfo> Click (int button, int screenX, int screenY)
{
// Adjust for 1-based coordinates
int adjustedX = screenX + 1;
int adjustedY = screenY + 1;
// Mouse press sequence
var sequence = $"\x1B[<{button};{adjustedX};{adjustedY}M";
foreach (char c in sequence)
{
yield return new ConsoleKeyInfo (c, ConsoleKey.None, false, false, false);
}
// Mouse release sequence
sequence = $"\x1B[<{button};{adjustedX};{adjustedY}m";
foreach (char c in sequence)
{
yield return new ConsoleKeyInfo (c, ConsoleKey.None, false, false, false);
}
}
}

View File

@@ -29,10 +29,11 @@ public static class With
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="testDriver"></param>
/// <param name="logWriter"></param>
/// <returns></returns>
public static GuiTestContext A (Func<Toplevel> toplevelFactory, int width, int height, TestDriver testDriver)
public static GuiTestContext A (Func<Toplevel> toplevelFactory, int width, int height, TestDriver testDriver, TextWriter? logWriter = null)
{
return new (toplevelFactory, width, height, testDriver, null, Timeout);
return new (toplevelFactory, width, height, testDriver, logWriter, Timeout);
}
/// <summary>
/// The global timeout to allow for any given application to run for before shutting down.

View File

@@ -59,7 +59,7 @@ public class TableViewTests (ITestOutputHelper output)
{
var tv = new TableView
{
Driver = ApplicationImpl.Instance.Driver,
App = ApplicationImpl.Instance,
Width = 20, Height = 4
};
@@ -683,7 +683,7 @@ public class TableViewTests (ITestOutputHelper output)
{
var tableView = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tableView.BeginInit ();
tableView.EndInit ();
@@ -765,7 +765,7 @@ public class TableViewTests (ITestOutputHelper output)
{
var tableView = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tableView.BeginInit ();
tableView.EndInit ();
@@ -830,7 +830,7 @@ public class TableViewTests (ITestOutputHelper output)
{
var tableView = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tableView.BeginInit ();
@@ -1579,7 +1579,7 @@ public class TableViewTests (ITestOutputHelper output)
{
var tv = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tv.SchemeName = "TopLevel";
tv.Viewport = new (0, 0, 50, 7);
@@ -2226,7 +2226,7 @@ public class TableViewTests (ITestOutputHelper output)
ApplicationImpl.Instance.Driver!.SetScreenSize (100, 100);
var tv = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tv.SchemeName = "TopLevel";
tv.Viewport = new (0, 0, 50, 6);
@@ -2433,7 +2433,7 @@ A B C
var tv = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
//tv.BeginInit (); tv.EndInit ();
@@ -3441,7 +3441,7 @@ A B C
{
var tableView = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tableView.BeginInit ();
tableView.EndInit ();
@@ -3473,7 +3473,7 @@ A B C
{
var tv = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver,
App = ApplicationImpl.Instance,
SchemeName = "TopLevel",
Viewport = new (0, 0, 25, 6)
};
@@ -3504,7 +3504,7 @@ A B C
{
var tableView = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tableView.SchemeName = "TopLevel";
@@ -3537,7 +3537,7 @@ A B C
{
var tv = new TableView ()
{
Driver = ApplicationImpl.Instance.Driver
App = ApplicationImpl.Instance
};
tv.BeginInit ();
tv.EndInit ();