From ea73d7b3d2f1a18cf1621842ce1943a963f8b816 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 10 Jun 2025 23:49:32 +0100 Subject: [PATCH 1/9] Fixes #4139. Application.Run isn't initializing properly by setting the Application.ForceDriver property --- .../UICatalog/Properties/launchSettings.json | 7 +++ .../App/Application.Initialization.cs | 11 ++++ Terminal.Gui/App/ApplicationImpl.cs | 11 +++- .../Drivers/V2/ConsoleDriverFacade.cs | 14 ++++- Terminal.Gui/Drivers/V2/NetOutput.cs | 16 +++++- Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs | 5 ++ Terminal.Gui/Drivers/V2/WindowsInput.cs | 16 +++++- Terminal.Gui/Drivers/V2/WindowsOutput.cs | 23 ++++++--- .../UnitTests/Application/ApplicationTests.cs | 51 ++++++++++++++++++- .../ConsoleDrivers/V2/ApplicationV2Tests.cs | 3 -- 10 files changed, 142 insertions(+), 15 deletions(-) diff --git a/Examples/UICatalog/Properties/launchSettings.json b/Examples/UICatalog/Properties/launchSettings.json index 0ef93b39c0..aac7bed7ba 100644 --- a/Examples/UICatalog/Properties/launchSettings.json +++ b/Examples/UICatalog/Properties/launchSettings.json @@ -32,6 +32,13 @@ "commandLineArgs": "dotnet UICatalog.dll --driver NetDriver", "distributionName": "" }, + "WSL: UICatalog --driver v2net": { + "commandName": "Executable", + "executablePath": "wsl", + "commandLineArgs": "dotnet UICatalog.dll --driver v2net", + "distributionName": "" + }, + "Benchmark All": { "commandName": "Project", "commandLineArgs": "--benchmark" diff --git a/Terminal.Gui/App/Application.Initialization.cs b/Terminal.Gui/App/Application.Initialization.cs index 61756e8e66..f9b2f942e7 100644 --- a/Terminal.Gui/App/Application.Initialization.cs +++ b/Terminal.Gui/App/Application.Initialization.cs @@ -77,6 +77,17 @@ internal static void InternalInit ( throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); } + var driverNameOrForceDriver = driverName ?? ForceDriver; + + if (driverNameOrForceDriver?.StartsWith ("v2") ?? false) + { + ApplicationImpl.ChangeInstance (new ApplicationV2 ()); + ApplicationImpl.Instance.Init (driver, driverNameOrForceDriver); + Debug.Assert (Driver is { }); + + return; + } + if (!calledViaRunT) { // Reset all class variables (Application is a singleton). diff --git a/Terminal.Gui/App/ApplicationImpl.cs b/Terminal.Gui/App/ApplicationImpl.cs index c9e9e8f474..8a3a78a36e 100644 --- a/Terminal.Gui/App/ApplicationImpl.cs +++ b/Terminal.Gui/App/ApplicationImpl.cs @@ -34,7 +34,7 @@ public static void ChangeInstance (IApplication newApplication) [RequiresDynamicCode ("AOT")] public virtual void Init (IConsoleDriver? driver = null, string? driverName = null) { - Application.InternalInit (driver, driverName); + Application.InternalInit (driver, driverName ?? Application.ForceDriver); } /// @@ -85,7 +85,12 @@ public virtual T Run (Func? errorHandler = null, IConsoleDri if (!Application.Initialized) { // Init() has NOT been called. - Application.InternalInit (driver, null, true); + Application.InternalInit (driver, Application.ForceDriver, true); + } + + if (Instance is ApplicationV2) + { + return Instance.Run (errorHandler, driver); } var top = new T (); @@ -227,6 +232,8 @@ public virtual void Shutdown () Application.OnInitializedChanged (this, new (in init)); } + + _lazyInstance = new (() => new ApplicationImpl ()); } /// diff --git a/Terminal.Gui/Drivers/V2/ConsoleDriverFacade.cs b/Terminal.Gui/Drivers/V2/ConsoleDriverFacade.cs index ea695008a2..c89c63965c 100644 --- a/Terminal.Gui/Drivers/V2/ConsoleDriverFacade.cs +++ b/Terminal.Gui/Drivers/V2/ConsoleDriverFacade.cs @@ -64,7 +64,19 @@ private void CreateClipboard () } /// Gets the location and size of the terminal screen. - public Rectangle Screen => new (new (0, 0), _output.GetWindowSize ()); + public Rectangle Screen + { + get + { + if (ConsoleDriver.RunningUnitTests) + { + // In unit tests, we don't have a real output, so we return an empty rectangle. + return Rectangle.Empty; + } + + return new (new (0, 0), _output.GetWindowSize ()); + } + } /// /// Gets or sets the clip rectangle that and are subject diff --git a/Terminal.Gui/Drivers/V2/NetOutput.cs b/Terminal.Gui/Drivers/V2/NetOutput.cs index 989aab735d..32ae497645 100644 --- a/Terminal.Gui/Drivers/V2/NetOutput.cs +++ b/Terminal.Gui/Drivers/V2/NetOutput.cs @@ -47,6 +47,11 @@ public void Write (ReadOnlySpan text) /// public void Write (IOutputBuffer buffer) { + if (ConsoleDriver.RunningUnitTests) + { + return; + } + if (Console.WindowHeight < 1 || buffer.Contents.Length != buffer.Rows * buffer.Cols || buffer.Rows != Console.WindowHeight) @@ -197,7 +202,16 @@ public void Write (IOutputBuffer buffer) } /// - public Size GetWindowSize () { return new (Console.WindowWidth, Console.WindowHeight); } + public Size GetWindowSize () + { + if (ConsoleDriver.RunningUnitTests) + { + // For unit tests, we return a default size. + return Size.Empty; + } + + return new (Console.WindowWidth, Console.WindowHeight); + } private void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth) { diff --git a/Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs b/Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs index 24cef5e9ab..ee3841c6ee 100644 --- a/Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs +++ b/Terminal.Gui/Drivers/V2/WindowSizeMonitor.cs @@ -20,6 +20,11 @@ public WindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer) /// public bool Poll () { + if (ConsoleDriver.RunningUnitTests) + { + return false; + } + Size size = _consoleOut.GetWindowSize (); if (size != _lastSize) diff --git a/Terminal.Gui/Drivers/V2/WindowsInput.cs b/Terminal.Gui/Drivers/V2/WindowsInput.cs index 4ded6a0890..11d01cb608 100644 --- a/Terminal.Gui/Drivers/V2/WindowsInput.cs +++ b/Terminal.Gui/Drivers/V2/WindowsInput.cs @@ -38,6 +38,12 @@ out uint lpNumberOfEventsRead public WindowsInput () { Logging.Logger.LogInformation ($"Creating {nameof (WindowsInput)}"); + + if (ConsoleDriver.RunningUnitTests) + { + return; + } + _inputHandle = GetStdHandle (STD_INPUT_HANDLE); GetConsoleMode (_inputHandle, out uint v); @@ -110,5 +116,13 @@ protected override bool Peek () } } - public override void Dispose () { SetConsoleMode (_inputHandle, _originalConsoleMode); } + public override void Dispose () + { + if (ConsoleDriver.RunningUnitTests) + { + return; + } + + SetConsoleMode (_inputHandle, _originalConsoleMode); + } } diff --git a/Terminal.Gui/Drivers/V2/WindowsOutput.cs b/Terminal.Gui/Drivers/V2/WindowsOutput.cs index 17fc2aff6e..fb8e26815f 100644 --- a/Terminal.Gui/Drivers/V2/WindowsOutput.cs +++ b/Terminal.Gui/Drivers/V2/WindowsOutput.cs @@ -68,6 +68,11 @@ public WindowsOutput () { Logging.Logger.LogInformation ($"Creating {nameof (WindowsOutput)}"); + if (ConsoleDriver.RunningUnitTests) + { + return; + } + _screenBuffer = CreateConsoleScreenBuffer ( DesiredAccess.GenericRead | DesiredAccess.GenericWrite, ShareMode.FileShareRead | ShareMode.FileShareWrite, @@ -171,12 +176,13 @@ public void Write (IOutputBuffer buffer) }; //size, ExtendedCharInfo [] charInfoBuffer, Coord , SmallRect window, - if (!WriteToConsole ( - new (buffer.Cols, buffer.Rows), - outputBuffer, - bufferCoords, - damageRegion, - Application.Driver!.Force16Colors)) + if (!ConsoleDriver.RunningUnitTests + && !WriteToConsole ( + new (buffer.Cols, buffer.Rows), + outputBuffer, + bufferCoords, + damageRegion, + Application.Driver!.Force16Colors)) { int err = Marshal.GetLastWin32Error (); @@ -312,6 +318,11 @@ public Size GetWindowSize () /// public void SetCursorVisibility (CursorVisibility visibility) { + if (ConsoleDriver.RunningUnitTests) + { + return; + } + if (Application.Driver!.Force16Colors) { var info = new WindowsConsole.ConsoleCursorInfo diff --git a/Tests/UnitTests/Application/ApplicationTests.cs b/Tests/UnitTests/Application/ApplicationTests.cs index eb9e8f908f..37b9b196ee 100644 --- a/Tests/UnitTests/Application/ApplicationTests.cs +++ b/Tests/UnitTests/Application/ApplicationTests.cs @@ -655,7 +655,17 @@ private void Init () Assert.NotNull (SynchronizationContext.Current); } - private void Shutdown () { Application.Shutdown (); } + private void Shutdown () + { + if (ApplicationImpl.Instance is ApplicationV2) + { + ApplicationImpl.Instance.Shutdown (); + } + else + { + Application.Shutdown (); + } + } #region RunTests @@ -1104,6 +1114,45 @@ public void Run_t_Does_Not_Creates_Top_Without_Init () Assert.Null (Application.Top); } + private class TestToplevel : Toplevel { } + + [Theory] + [InlineData ("v2win", typeof (ConsoleDriverFacade))] + [InlineData ("v2net", typeof (ConsoleDriverFacade))] + [InlineData ("FakeDriver", typeof (FakeDriver))] + [InlineData ("NetDriver", typeof (NetDriver))] + [InlineData ("WindowsDriver", typeof (WindowsDriver))] + [InlineData ("CursesDriver", typeof (CursesDriver))] + public void Run_T_Call_Init_ForceDriver_Should_Pick_Correct_Driver (string driverName, Type expectedType) + { + var result = false; + + Task.Run (() => + { + Task.Delay (300).Wait (); + }).ContinueWith ( + (t, _) => + { + // no longer loading + Application.Invoke (() => + { + result = true; + Application.RequestStop (); + }); + }, + TaskScheduler.FromCurrentSynchronizationContext ()); + + Application.ForceDriver = driverName; + Application.Run (); + Assert.NotNull (Application.Driver); + Assert.Equal (expectedType, Application.Driver?.GetType ()); + Assert.NotNull (Application.Top); + Assert.False (Application.Top!.Running); + Application.Top!.Dispose (); + Shutdown (); + Assert.True (result); + } + // TODO: Add tests for Run that test errorHandler #endregion diff --git a/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs b/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs index 6fa4c0f1b5..833d28c086 100644 --- a/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs +++ b/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs @@ -362,7 +362,6 @@ public void InitRunShutdown_QuitKey_Quits () if (Application.Top != null) { Application.RaiseKeyDownEvent (Application.QuitKey); - return false; } return false; @@ -575,8 +574,6 @@ public void Open_Calls_ContinueWith_On_UIThread () { b.NewKeyDownEvent (Key.Enter); b.NewKeyUpEvent (Key.Enter); - - return false; } return false; From f46f60b87f175438aa378860c918f4ce30b78e85 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 00:35:07 +0100 Subject: [PATCH 2/9] Trying fix unit tests --- Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs | 4 ++++ Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs b/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs index 833d28c086..0a34417fac 100644 --- a/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs +++ b/Tests/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs @@ -7,6 +7,10 @@ namespace UnitTests.ConsoleDrivers.V2; public class ApplicationV2Tests { + public ApplicationV2Tests () + { + ConsoleDriver.RunningUnitTests = true; + } private ApplicationV2 NewApplicationV2 () { diff --git a/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs b/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs index 8b7c7a7b64..f8c1d8e422 100644 --- a/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs @@ -3,6 +3,11 @@ namespace UnitTests.ConsoleDrivers.V2; public class WindowSizeMonitorTests { + public WindowSizeMonitorTests () + { + ConsoleDriver.RunningUnitTests = false; + } + [Fact] public void TestWindowSizeMonitor_RaisesEventWhenChanges () { From db23e753494ed06e3f2393477083769d79712174 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 00:58:52 +0100 Subject: [PATCH 3/9] Only to force again CI tests because I haven't errors locally --- Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs b/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs index f8c1d8e422..89dde8af1b 100644 --- a/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/V2/WindowSizeMonitorTests.cs @@ -75,7 +75,4 @@ public void TestWindowSizeMonitor_DoesNotRaiseEventWhen_NoChanges () Assert.Single (result); Assert.Equal (new Size (30, 20), result [0].Size); } - - - } From 5b6021095900f02afd1aa59732cec8320f3689c9 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 01:09:35 +0100 Subject: [PATCH 4/9] This should pass, unless RunningUnitTests is set to false somewhere --- Tests/UnitTests/Application/ApplicationTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/UnitTests/Application/ApplicationTests.cs b/Tests/UnitTests/Application/ApplicationTests.cs index 37b9b196ee..8492a8e016 100644 --- a/Tests/UnitTests/Application/ApplicationTests.cs +++ b/Tests/UnitTests/Application/ApplicationTests.cs @@ -1125,6 +1125,8 @@ private class TestToplevel : Toplevel { } [InlineData ("CursesDriver", typeof (CursesDriver))] public void Run_T_Call_Init_ForceDriver_Should_Pick_Correct_Driver (string driverName, Type expectedType) { + Assert.True (ConsoleDriver.RunningUnitTests); + var result = false; Task.Run (() => From 404dd832abfdc11240f3aa2f173ca48c1e250a30 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 19:26:29 +0100 Subject: [PATCH 5/9] Fix Unix unit tests and failures via ReSharper --- Terminal.Gui/Drivers/NetDriver/NetEvents.cs | 8 +++++++- Terminal.Gui/Drivers/V2/NetInput.cs | 16 +++++++++++++++- .../FluentTests/FileDialogFluentTests.cs | 4 +++- .../FluentTests/MenuBarv2Tests.cs | 2 ++ .../FluentTests/PopverMenuTests.cs | 12 +++++++++--- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Terminal.Gui/Drivers/NetDriver/NetEvents.cs b/Terminal.Gui/Drivers/NetDriver/NetEvents.cs index 4a7e662692..65e2faa2d8 100644 --- a/Terminal.Gui/Drivers/NetDriver/NetEvents.cs +++ b/Terminal.Gui/Drivers/NetDriver/NetEvents.cs @@ -19,6 +19,11 @@ public NetEvents (IConsoleDriver consoleDriver) { _consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver)); + if (ConsoleDriver.RunningUnitTests) + { + return; + } + Task.Run (() => { try @@ -29,7 +34,8 @@ public NetEvents (IConsoleDriver consoleDriver) { } }, _netEventsDisposed.Token); - Task.Run (() => { + Task.Run (() => + { try { CheckWindowSizeChange (); diff --git a/Terminal.Gui/Drivers/V2/NetInput.cs b/Terminal.Gui/Drivers/V2/NetInput.cs index 7cfe488d36..518c77e557 100644 --- a/Terminal.Gui/Drivers/V2/NetInput.cs +++ b/Terminal.Gui/Drivers/V2/NetInput.cs @@ -17,6 +17,12 @@ public class NetInput : ConsoleInput, INetInput public NetInput () { Logging.Logger.LogInformation ($"Creating {nameof (NetInput)}"); + + if (ConsoleDriver.RunningUnitTests) + { + return; + } + PlatformID p = Environment.OSVersion.Platform; if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) @@ -39,7 +45,15 @@ public NetInput () } /// - protected override bool Peek () { return Console.KeyAvailable; } + protected override bool Peek () + { + if (ConsoleDriver.RunningUnitTests) + { + return false; + } + + return Console.KeyAvailable; + } /// protected override IEnumerable Read () diff --git a/Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs b/Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs index 936bebba22..47a819fc78 100644 --- a/Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs +++ b/Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs @@ -1,4 +1,5 @@ -using System.IO.Abstractions; +using System.Globalization; +using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using System.Runtime.InteropServices; using TerminalGuiFluentTesting; @@ -12,6 +13,7 @@ public class FileDialogFluentTests public FileDialogFluentTests (ITestOutputHelper outputHelper) { + CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; _out = new TestOutputWriter (outputHelper); } diff --git a/Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs b/Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs index 76e0a4d7f2..f6116c5d57 100644 --- a/Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs +++ b/Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Reflection; using TerminalGuiFluentTesting; using Xunit.Abstractions; @@ -13,6 +14,7 @@ public class MenuBarv2Tests public MenuBarv2Tests (ITestOutputHelper outputHelper) { + CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; _out = new TestOutputWriter (outputHelper); } diff --git a/Tests/IntegrationTests/FluentTests/PopverMenuTests.cs b/Tests/IntegrationTests/FluentTests/PopverMenuTests.cs index 15f56b675a..3a7f975d1b 100644 --- a/Tests/IntegrationTests/FluentTests/PopverMenuTests.cs +++ b/Tests/IntegrationTests/FluentTests/PopverMenuTests.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Globalization; using TerminalGuiFluentTesting; using Xunit.Abstractions; @@ -7,9 +7,15 @@ namespace IntegrationTests.FluentTests; /// /// Tests for the PopoverMenu class /// -public class PopoverMenuTests (ITestOutputHelper outputHelper) +public class PopoverMenuTests { - private readonly TextWriter _out = new TestOutputWriter (outputHelper); + private readonly TextWriter _out; + + public PopoverMenuTests (ITestOutputHelper outputHelper) + { + CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; + _out = new TestOutputWriter (outputHelper); + } [Theory] [ClassData (typeof (V2TestDrivers))] From 15d68c600a8bdadf1b2b31d8704578ed9157a70a Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 21:00:07 +0100 Subject: [PATCH 6/9] Changes suggested by @tig --- Examples/UICatalog/UICatalog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/UICatalog/UICatalog.cs b/Examples/UICatalog/UICatalog.cs index fbd1296e85..c04eabcb3a 100644 --- a/Examples/UICatalog/UICatalog.cs +++ b/Examples/UICatalog/UICatalog.cs @@ -54,7 +54,7 @@ namespace UICatalog; /// public class UICatalog { - private static string _forceDriver = string.Empty; + private static string? _forceDriver = null; public static string LogFilePath { get; set; } = string.Empty; public static LoggingLevelSwitch LogLevelSwitch { get; } = new (); From 3bc1f97220b93f4ddd81d1b247af77e95461e265 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 21:00:43 +0100 Subject: [PATCH 7/9] Prevent empty string --- Terminal.Gui/App/ApplicationImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Terminal.Gui/App/ApplicationImpl.cs b/Terminal.Gui/App/ApplicationImpl.cs index 8a3a78a36e..111b9783dc 100644 --- a/Terminal.Gui/App/ApplicationImpl.cs +++ b/Terminal.Gui/App/ApplicationImpl.cs @@ -34,7 +34,7 @@ public static void ChangeInstance (IApplication newApplication) [RequiresDynamicCode ("AOT")] public virtual void Init (IConsoleDriver? driver = null, string? driverName = null) { - Application.InternalInit (driver, driverName ?? Application.ForceDriver); + Application.InternalInit (driver, string.IsNullOrWhiteSpace (driverName) ? Application.ForceDriver : driverName); } /// From 85d35691508a8402f4ee5e6f25a8bada5bf5409e Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Jun 2025 23:18:28 +0100 Subject: [PATCH 8/9] Centralize all the entry logic in the InternalInit method --- .../App/Application.Initialization.cs | 40 ++++++++---------- .../UnitTests/Application/ApplicationTests.cs | 42 +++++++++++++++++++ 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Terminal.Gui/App/Application.Initialization.cs b/Terminal.Gui/App/Application.Initialization.cs index f9b2f942e7..b6650b38a1 100644 --- a/Terminal.Gui/App/Application.Initialization.cs +++ b/Terminal.Gui/App/Application.Initialization.cs @@ -40,11 +40,6 @@ public static partial class Application // Initialization (Init/Shutdown) [RequiresDynamicCode ("AOT")] public static void Init (IConsoleDriver? driver = null, string? driverName = null) { - if (driverName?.StartsWith ("v2") ?? false) - { - ApplicationImpl.ChangeInstance (new ApplicationV2 ()); - } - ApplicationImpl.Instance.Init (driver, driverName); } @@ -77,16 +72,7 @@ internal static void InternalInit ( throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); } - var driverNameOrForceDriver = driverName ?? ForceDriver; - - if (driverNameOrForceDriver?.StartsWith ("v2") ?? false) - { - ApplicationImpl.ChangeInstance (new ApplicationV2 ()); - ApplicationImpl.Instance.Init (driver, driverNameOrForceDriver); - Debug.Assert (Driver is { }); - - return; - } + ForceDriver = string.IsNullOrWhiteSpace (driverName) ? ForceDriver : driverName; if (!calledViaRunT) { @@ -94,12 +80,6 @@ internal static void InternalInit ( ResetState (ignoreDisposed: true); } - Debug.Assert (Navigation is null); - Navigation = new (); - - Debug.Assert(Popover is null); - Popover = new (); - // For UnitTests if (driver is { }) { @@ -116,8 +96,6 @@ internal static void InternalInit ( } } - AddKeyBindings (); - // Ignore Configuration for ForceDriver if driverName is specified if (!string.IsNullOrEmpty (driverName)) { @@ -148,6 +126,14 @@ internal static void InternalInit ( { Driver = (IConsoleDriver)Activator.CreateInstance (driverType)!; } + else if (ForceDriver?.StartsWith ("v2") ?? false) + { + ApplicationImpl.ChangeInstance (new ApplicationV2 ()); + ApplicationImpl.Instance.Init (driver, ForceDriver); + Debug.Assert (Driver is { }); + + return; + } else { throw new ArgumentException ( @@ -157,6 +143,14 @@ internal static void InternalInit ( } } + Debug.Assert (Navigation is null); + Navigation = new (); + + Debug.Assert (Popover is null); + Popover = new (); + + AddKeyBindings (); + try { MainLoop = Driver!.Init (); diff --git a/Tests/UnitTests/Application/ApplicationTests.cs b/Tests/UnitTests/Application/ApplicationTests.cs index 8492a8e016..40d2ca5389 100644 --- a/Tests/UnitTests/Application/ApplicationTests.cs +++ b/Tests/UnitTests/Application/ApplicationTests.cs @@ -1155,6 +1155,48 @@ public void Run_T_Call_Init_ForceDriver_Should_Pick_Correct_Driver (string drive Assert.True (result); } + [Fact] + public void Run_T_With_Legacy_Driver_Does_Not_Call_ResetState_After_Init () + { + Assert.False (Application.Initialized); + Application.Init (); + Assert.True (Application.Initialized); + Application.Iteration += (_, _) => Application.RequestStop (); + Application.Run (); + Assert.NotNull (Application.Driver); + Assert.NotNull (Application.Top); + Assert.False (Application.Top!.Running); + Application.Top!.Dispose (); + Shutdown (); + } + + [Fact] + public void Run_T_With_V2_Driver_Does_Not_Call_ResetState_After_Init () + { + Assert.False (Application.Initialized); + Application.Init (null, "v2net"); + Assert.True (Application.Initialized); + Task.Run (() => + { + Task.Delay (300).Wait (); + }).ContinueWith ( + (t, _) => + { + // no longer loading + Application.Invoke (() => + { + Application.RequestStop (); + }); + }, + TaskScheduler.FromCurrentSynchronizationContext ()); + Application.Run (); + Assert.NotNull (Application.Driver); + Assert.NotNull (Application.Top); + Assert.False (Application.Top!.Running); + Application.Top!.Dispose (); + Shutdown (); + } + // TODO: Add tests for Run that test errorHandler #endregion From eaef2f326137f241506dedcb88555e2ac7c044fb Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 12 Jun 2025 15:47:50 +0100 Subject: [PATCH 9/9] Change GetDriverTypes to return a tuple --- .../UICatalog/Properties/launchSettings.json | 11 ++++++++++- Examples/UICatalog/UICatalog.cs | 6 +----- Terminal.Gui/App/Application.Initialization.cs | 16 ++++++++++------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Examples/UICatalog/Properties/launchSettings.json b/Examples/UICatalog/Properties/launchSettings.json index aac7bed7ba..fe464d1000 100644 --- a/Examples/UICatalog/Properties/launchSettings.json +++ b/Examples/UICatalog/Properties/launchSettings.json @@ -12,6 +12,10 @@ "commandName": "Project", "commandLineArgs": "--driver WindowsDriver" }, + "UICatalog --driver v2": { + "commandName": "Project", + "commandLineArgs": "--driver v2 -dl Trace" + }, "UICatalog --driver v2win": { "commandName": "Project", "commandLineArgs": "--driver v2win -dl Trace" @@ -32,13 +36,18 @@ "commandLineArgs": "dotnet UICatalog.dll --driver NetDriver", "distributionName": "" }, + "WSL: UICatalog --driver v2": { + "commandName": "Executable", + "executablePath": "wsl", + "commandLineArgs": "dotnet UICatalog.dll --driver v2", + "distributionName": "" + }, "WSL: UICatalog --driver v2net": { "commandName": "Executable", "executablePath": "wsl", "commandLineArgs": "dotnet UICatalog.dll --driver v2net", "distributionName": "" }, - "Benchmark All": { "commandName": "Project", "commandLineArgs": "--benchmark" diff --git a/Examples/UICatalog/UICatalog.cs b/Examples/UICatalog/UICatalog.cs index c04eabcb3a..ee968d17bd 100644 --- a/Examples/UICatalog/UICatalog.cs +++ b/Examples/UICatalog/UICatalog.cs @@ -77,11 +77,7 @@ private static int Main (string [] args) // If no driver is provided, the default driver is used. Option driverOption = new Option ("--driver", "The IConsoleDriver to use.").FromAmong ( - Application.GetDriverTypes () - .Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d)) - .Select (d => d!.Name) - .Union (["v2", "v2win", "v2net"]) - .ToArray () + Application.GetDriverTypes ().Item2.ToArray ()! ); driverOption.AddAlias ("-d"); driverOption.AddAlias ("--d"); diff --git a/Terminal.Gui/App/Application.Initialization.cs b/Terminal.Gui/App/Application.Initialization.cs index b6650b38a1..b5c9b1d1b6 100644 --- a/Terminal.Gui/App/Application.Initialization.cs +++ b/Terminal.Gui/App/Application.Initialization.cs @@ -72,8 +72,6 @@ internal static void InternalInit ( throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); } - ForceDriver = string.IsNullOrWhiteSpace (driverName) ? ForceDriver : driverName; - if (!calledViaRunT) { // Reset all class variables (Application is a singleton). @@ -119,7 +117,7 @@ internal static void InternalInit ( } else { - List drivers = GetDriverTypes (); + (List drivers, List driverTypeNames) = GetDriverTypes (); Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase)); if (driverType is { }) @@ -206,10 +204,10 @@ internal static void UnsubscribeDriverEvents () private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); } private static void Driver_MouseEvent (object? sender, MouseEventArgs e) { RaiseMouseEvent (e); } - /// Gets of list of types that are available. + /// Gets of list of types and type names that are available. /// [RequiresUnreferencedCode ("AOT")] - public static List GetDriverTypes () + public static (List, List) GetDriverTypes () { // use reflection to get the list of drivers List driverTypes = new (); @@ -225,7 +223,13 @@ internal static void UnsubscribeDriverEvents () } } - return driverTypes; + List driverTypeNames = driverTypes + .Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d)) + .Select (d => d!.Name) + .Union (["v2", "v2win", "v2net"]) + .ToList ()!; + + return (driverTypes, driverTypeNames); } /// Shutdown an application initialized with .