diff --git a/.editorconfig b/.editorconfig index 95013c249..fa758e3bb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -82,8 +82,8 @@ dotnet_diagnostic.cs0464.severity = warning dotnet_diagnostic.cs0465.severity = warning dotnet_diagnostic.cs0469.severity = warning dotnet_diagnostic.cs0472.severity = warning -dotnet_diagnostic.cs0612.severity = warning -dotnet_diagnostic.cs0618.severity = warning +dotnet_diagnostic.cs0612.severity = none +dotnet_diagnostic.cs0618.severity = none dotnet_diagnostic.cs0628.severity = warning dotnet_diagnostic.cs0642.severity = warning dotnet_diagnostic.cs0649.severity = warning @@ -94,7 +94,7 @@ dotnet_diagnostic.cs0659.severity = warning dotnet_diagnostic.cs0660.severity = warning dotnet_diagnostic.cs0661.severity = warning dotnet_diagnostic.cs0665.severity = warning -dotnet_diagnostic.cs0672.severity = warning +dotnet_diagnostic.cs0672.severity = none dotnet_diagnostic.cs0675.severity = warning dotnet_diagnostic.cs0693.severity = warning dotnet_diagnostic.cs0728.severity = warning diff --git a/Examples/UICatalog/Scenarios/Adornments.cs b/Examples/UICatalog/Scenarios/Adornments.cs index 5e0efc628..938d23a53 100644 --- a/Examples/UICatalog/Scenarios/Adornments.cs +++ b/Examples/UICatalog/Scenarios/Adornments.cs @@ -26,7 +26,7 @@ public class Adornments : Scenario X = Pos.AnchorEnd () }; - editor.Border.Thickness = new (1, 2, 1, 1); + editor.Border!.Thickness = new (1, 2, 1, 1); app.Add (editor); @@ -71,7 +71,7 @@ public class Adornments : Scenario Width = 40, Height = 6 // TODO: Use Dim.Auto }; - label.Border.Thickness = new (1, 3, 1, 1); + label.Border!.Thickness = new (1, 3, 1, 1); var btnButtonInWindow = new Button { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" }; @@ -84,13 +84,13 @@ public class Adornments : Scenario SchemeName = "Dialog" }; - window.Margin.Data = "Margin"; - window.Margin.Text = "Margin Text"; - window.Margin.Thickness = new (0); + window.Margin!.Data = "Margin"; + window.Margin!.Text = "Margin Text"; + window.Margin!.Thickness = new (0); - window.Border.Data = "Border"; - window.Border.Text = "Border Text"; - window.Border.Thickness = new (0); + window.Border!.Data = "Border"; + window.Border!.Text = "Border Text"; + window.Border!.Thickness = new (0); window.Padding.Data = "Padding"; window.Padding.Text = "Padding Text line 1\nPadding Text line 3\nPadding Text line 3\nPadding Text line 4\nPadding Text line 5"; @@ -134,14 +134,14 @@ public class Adornments : Scenario }; btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok"); btnButtonInPadding.BorderStyle = LineStyle.Dashed; - btnButtonInPadding.Border.Thickness = new (1, 1, 1, 1); + btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1); window.Padding.Add (btnButtonInPadding); #if SUBVIEW_BASED_BORDER - btnButtonInPadding.Border.CloseButton.Visible = true; + btnButtonInPadding.Border!.CloseButton.Visible = true; - view.Border.CloseButton.Visible = true; - view.Border.CloseButton.Accept += (s, e) => + view.Border!.CloseButton.Visible = true; + view.Border!.CloseButton.Accept += (s, e) => { MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok"); e.Handled = true; diff --git a/Examples/UICatalog/Scenarios/AllViewsTester.cs b/Examples/UICatalog/Scenarios/AllViewsTester.cs index f967742bc..99fbbdb50 100644 --- a/Examples/UICatalog/Scenarios/AllViewsTester.cs +++ b/Examples/UICatalog/Scenarios/AllViewsTester.cs @@ -38,7 +38,7 @@ public class AllViewsTester : Scenario // Set the BorderStyle we use for all subviews, but disable the app border thickness app.Border!.LineStyle = LineStyle.Heavy; - app.Border.Thickness = new (0); + app.Border!.Thickness = new (0); _viewClasses = GetAllViewClassesCollection () diff --git a/Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs b/Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs index 9a68b2567..ad4f881ba 100644 --- a/Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs +++ b/Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs @@ -112,7 +112,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario break; case "CSI_ReportTerminalSizeInChars": - selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportTerminalSizeInChars; + selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportWindowSizeInChars; break; case "CSI_RequestCursorPositionReport": diff --git a/Examples/UICatalog/Scenarios/Bars.cs b/Examples/UICatalog/Scenarios/Bars.cs index 226e18e26..af79c0cbd 100644 --- a/Examples/UICatalog/Scenarios/Bars.cs +++ b/Examples/UICatalog/Scenarios/Bars.cs @@ -40,7 +40,7 @@ public class Bars : Scenario SchemeName = "Toplevel", Source = new ListWrapper (eventSource) }; - eventLog.Border.Thickness = new (0, 1, 0, 0); + eventLog.Border!.Thickness = new (0, 1, 0, 0); Application.Top.Add (eventLog); FrameView menuBarLikeExamples = new () diff --git a/Examples/UICatalog/Scenarios/Clipping.cs b/Examples/UICatalog/Scenarios/Clipping.cs index 2cebee301..b9bb47528 100644 --- a/Examples/UICatalog/Scenarios/Clipping.cs +++ b/Examples/UICatalog/Scenarios/Clipping.cs @@ -151,7 +151,7 @@ public class Clipping : Scenario //tiled.Padding.Thickness = new (1); //tiled.Padding.Diagnostics = ViewDiagnosticFlags.Thickness; - //tiled.Margin.Thickness = new (1); + //tiled.Margin!.Thickness = new (1); FrameView fv = new () { diff --git a/Examples/UICatalog/Scenarios/DimAutoDemo.cs b/Examples/UICatalog/Scenarios/DimAutoDemo.cs index 7c99647e4..efad9eeb7 100644 --- a/Examples/UICatalog/Scenarios/DimAutoDemo.cs +++ b/Examples/UICatalog/Scenarios/DimAutoDemo.cs @@ -56,7 +56,7 @@ public class DimAutoDemo : Scenario Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: Dim.Percent (25)), Height = Dim.Auto (DimAutoStyle.Content, minimumContentDim: 10) }; - dimAutoFrameView.Margin.Thickness = new Thickness (1); + dimAutoFrameView.Margin!.Thickness = new Thickness (1); dimAutoFrameView.ValidatePosDim = true; var textEdit = new TextView diff --git a/Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs b/Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs index 74d7acee8..30c3ffda4 100644 --- a/Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs +++ b/Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs @@ -99,7 +99,7 @@ public class AdornmentsEditor : EditorBase SuperViewRendersLineCanvas = true, BorderStyle = LineStyle.Single }; - MarginEditor.Border!.Thickness = MarginEditor.Border.Thickness with { Bottom = 0 }; + MarginEditor.Border!.Thickness = MarginEditor.Border!.Thickness with { Bottom = 0 }; Add (MarginEditor); BorderEditor = new () @@ -109,7 +109,7 @@ public class AdornmentsEditor : EditorBase SuperViewRendersLineCanvas = true, BorderStyle = LineStyle.Single }; - BorderEditor.Border!.Thickness = BorderEditor.Border.Thickness with { Bottom = 0 }; + BorderEditor.Border!.Thickness = BorderEditor.Border!.Thickness with { Bottom = 0 }; Add (BorderEditor); PaddingEditor = new () @@ -119,7 +119,7 @@ public class AdornmentsEditor : EditorBase SuperViewRendersLineCanvas = true, BorderStyle = LineStyle.Single }; - PaddingEditor.Border!.Thickness = PaddingEditor.Border.Thickness with { Bottom = 0 }; + PaddingEditor.Border!.Thickness = PaddingEditor.Border!.Thickness with { Bottom = 0 }; Add (PaddingEditor); Width = Dim.Auto (maximumContentDim: Dim.Func (_ => MarginEditor.Frame.Width - 2)); diff --git a/Examples/UICatalog/Scenarios/GraphViewExample.cs b/Examples/UICatalog/Scenarios/GraphViewExample.cs index 530acf8e4..507a0c475 100644 --- a/Examples/UICatalog/Scenarios/GraphViewExample.cs +++ b/Examples/UICatalog/Scenarios/GraphViewExample.cs @@ -144,8 +144,8 @@ public class GraphViewExample : Scenario Height = Dim.Fill (1), BorderStyle = LineStyle.Single }; - _graphView.Border.Thickness = _thickness; - _graphView.Margin.Thickness = _thickness; + _graphView.Border!.Thickness = _thickness; + _graphView.Margin!.Thickness = _thickness; _graphView.Padding.Thickness = _thickness; app.Add (_graphView); @@ -955,14 +955,14 @@ public class GraphViewExample : Scenario if (_miShowBorder.Checked == true) { _graphView.BorderStyle = LineStyle.Single; - _graphView.Border.Thickness = _thickness; - _graphView.Margin.Thickness = _thickness; + _graphView.Border!.Thickness = _thickness; + _graphView.Margin!.Thickness = _thickness; _graphView.Padding.Thickness = _thickness; } else { _graphView.BorderStyle = LineStyle.None; - _graphView.Margin.Thickness = Thickness.Empty; + _graphView.Margin!.Thickness = Thickness.Empty; _graphView.Padding.Thickness = Thickness.Empty; } } diff --git a/Examples/UICatalog/Scenarios/LineCanvasExperiment.cs b/Examples/UICatalog/Scenarios/LineCanvasExperiment.cs index 85786a40e..6a826e4be 100644 --- a/Examples/UICatalog/Scenarios/LineCanvasExperiment.cs +++ b/Examples/UICatalog/Scenarios/LineCanvasExperiment.cs @@ -130,9 +130,9 @@ public class LineCanvasExperiment : Scenario // //Scheme = Colors.Schemes ["Error"], // SuperViewRendersLineCanvas = true //}; - //marginWindow.Margin.Scheme = Colors.Schemes ["Error"]; - //marginWindow.Margin.Thickness = new (1); - //marginWindow.Border.Thickness = new (1, 2, 1, 1); + //marginWindow.Margin!.Scheme = Colors.Schemes ["Error"]; + //marginWindow.Margin!.Thickness = new (1); + //marginWindow.Border!.Thickness = new (1, 2, 1, 1); //frame1.Add (marginWindow); diff --git a/Examples/UICatalog/Scenarios/PosAlignDemo.cs b/Examples/UICatalog/Scenarios/PosAlignDemo.cs index 5a9317aac..205a3c535 100644 --- a/Examples/UICatalog/Scenarios/PosAlignDemo.cs +++ b/Examples/UICatalog/Scenarios/PosAlignDemo.cs @@ -248,13 +248,13 @@ public sealed class PosAlignDemo : Scenario { addedViewsUpDown.X = Pos.Align (_horizAligner.Alignment); addedViewsUpDown.Y = Pos.Top (alignRadioGroup); - addedViewsUpDown.Border.Thickness = new (0, 1, 0, 0); + addedViewsUpDown.Border!.Thickness = new (0, 1, 0, 0); } else { addedViewsUpDown.X = Pos.Left (alignRadioGroup); addedViewsUpDown.Y = Pos.Align (_vertAligner.Alignment); - addedViewsUpDown.Border.Thickness = new (1, 0, 0, 0); + addedViewsUpDown.Border!.Thickness = new (1, 0, 0, 0); } addedViewsUpDown.ValueChanging += (s, e) => @@ -319,7 +319,7 @@ public sealed class PosAlignDemo : Scenario aligner.Alignment, aligner.AlignmentModes, posAlign!.GroupId); - view.Margin.Thickness = new (_leftMargin, view.Margin.Thickness.Top, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom); + view.Margin!.Thickness = new (_leftMargin, view.Margin!.Thickness.Top, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom); } else { @@ -330,7 +330,7 @@ public sealed class PosAlignDemo : Scenario aligner.AlignmentModes, posAlign!.GroupId); - view.Margin.Thickness = new (view.Margin.Thickness.Left, _topMargin, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom); + view.Margin!.Thickness = new (view.Margin!.Thickness.Left, _topMargin, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom); } } } diff --git a/Examples/UICatalog/Scenarios/Shortcuts.cs b/Examples/UICatalog/Scenarios/Shortcuts.cs index fc9843b3c..a4443146e 100644 --- a/Examples/UICatalog/Scenarios/Shortcuts.cs +++ b/Examples/UICatalog/Scenarios/Shortcuts.cs @@ -337,7 +337,7 @@ public class Shortcuts : Scenario if (framedShortcut.CommandView.Margin is { }) { - framedShortcut.CommandView.Margin.SchemeName = framedShortcut.CommandView.SchemeName = "Error"; + framedShortcut.CommandView.Margin!.SchemeName = framedShortcut.CommandView.SchemeName = "Error"; framedShortcut.HelpView.Margin!.SchemeName = framedShortcut.HelpView.SchemeName = "Dialog"; framedShortcut.KeyView.Margin!.SchemeName = framedShortcut.KeyView.SchemeName = "Menu"; } diff --git a/Examples/UICatalog/Scenarios/ViewportSettings.cs b/Examples/UICatalog/Scenarios/ViewportSettings.cs index fa801e37c..4e430171c 100644 --- a/Examples/UICatalog/Scenarios/ViewportSettings.cs +++ b/Examples/UICatalog/Scenarios/ViewportSettings.cs @@ -178,10 +178,10 @@ public class ViewportSettings : Scenario buttonAnchored.Accepting += (sender, args) => MessageBox.Query ("Hi", $"You pressed {((Button)sender)?.Text}", "_Ok"); view.Margin!.Data = "Margin"; - view.Margin.Thickness = new (0); + view.Margin!.Thickness = new (0); view.Border!.Data = "Border"; - view.Border.Thickness = new (3); + view.Border!.Thickness = new (3); view.Padding.Data = "Padding"; diff --git a/Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs b/Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs index 0a28a74fa..fcf57343a 100644 --- a/Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs +++ b/Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs @@ -43,7 +43,7 @@ public class WindowsAndFrameViews : Scenario Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable }; win.Padding.Thickness = new (padding); - win.Margin.Thickness = new (margin); + win.Margin!.Thickness = new (margin); var paddingButton = new Button { diff --git a/Examples/UICatalog/UICatalog.cs b/Examples/UICatalog/UICatalog.cs index acbba9711..e7b6d2340 100644 --- a/Examples/UICatalog/UICatalog.cs +++ b/Examples/UICatalog/UICatalog.cs @@ -451,7 +451,7 @@ public class UICatalog scenario.StartBenchmark (); } - Application.Init (driverName: _forceDriver); + Application.ForceDriver = _forceDriver!; scenario.Main (); @@ -517,7 +517,7 @@ public class UICatalog if (benchmarkWindow.Border is { }) { - benchmarkWindow.Border.Thickness = new (0, 0, 0, 0); + benchmarkWindow.Border!.Thickness = new (0, 0, 0, 0); } TableView resultsTableView = new () diff --git a/Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs b/Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs index 6eeab40dd..e50992546 100644 --- a/Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs +++ b/Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs @@ -1,7 +1,8 @@ -using Terminal.Gui.Input; +using Terminal.Gui.Analyzers; +using Terminal.Gui.Input; using Terminal.Gui.Views; -namespace Terminal.Gui.Analyzers.Tests; +namespace Analyzers.Tests; public class HandledEventArgsAnalyzerTests { diff --git a/Terminal.Gui/App/Application.Lifecycle.cs b/Terminal.Gui/App/Application.Lifecycle.cs index 4aa915d0f..9cd2b7996 100644 --- a/Terminal.Gui/App/Application.Lifecycle.cs +++ b/Terminal.Gui/App/Application.Lifecycle.cs @@ -40,26 +40,6 @@ public static partial class Application // Lifecycle (Init/Shutdown) [RequiresDynamicCode ("AOT")] public static void Init (IConsoleDriver? driver = null, string? driverName = null) { - // Check if this is a request for a legacy driver (like FakeDriver) - // that isn't supported by the modern application architecture - if (driver is null) - { - var driverNameToCheck = string.IsNullOrWhiteSpace (driverName) ? ForceDriver : driverName; - if (!string.IsNullOrEmpty (driverNameToCheck)) - { - (List drivers, List driverTypeNames) = GetDriverTypes (); - Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (driverNameToCheck, StringComparison.InvariantCultureIgnoreCase)); - - // If it's a legacy IConsoleDriver (not a Facade), use InternalInit which supports legacy drivers - if (driverType is { } && !typeof (IConsoleDriverFacade).IsAssignableFrom (driverType)) - { - InternalInit (driver, driverName); - return; - } - } - } - - // Otherwise delegate to the ApplicationImpl instance (which uses the modern architecture) ApplicationImpl.Instance.Init (driver, driverName ?? ForceDriver); } @@ -69,96 +49,6 @@ public static partial class Application // Lifecycle (Init/Shutdown) set => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId = value; } - // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop. - // - // Called from: - // - // Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset. - // Run() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run() to be called without calling Init first. - // Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset. - // - // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset. - [RequiresUnreferencedCode ("AOT")] - [RequiresDynamicCode ("AOT")] - internal static void InternalInit ( - IConsoleDriver? driver = null, - string? driverName = null, - bool calledViaRunT = false - ) - { - if (Initialized && driver is null) - { - return; - } - - if (Initialized) - { - throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown."); - } - - if (!calledViaRunT) - { - // Reset all class variables (Application is a singleton). - ResetState (ignoreDisposed: true); - } - - // For UnitTests - if (driver is { }) - { - Driver = driver; - } - - // Ignore Configuration for ForceDriver if driverName is specified - if (!string.IsNullOrEmpty (driverName)) - { - ForceDriver = driverName; - } - - // Check if we need to use a legacy driver (like FakeDriver) - // or go through the modern application architecture - if (Driver is null) - { - ApplicationImpl.Instance.Init (driver, driverName); - Debug.Assert (Driver is { }); - return; - } - - Debug.Assert (Navigation is null); - Navigation = new (); - - Debug.Assert (Popover is null); - Popover = new (); - - try - { - Driver!.Init (); - SubscribeDriverEvents (); - } - catch (InvalidOperationException ex) - { - // This is a case where the driver is unable to initialize the console. - // This can happen if the console is already in use by another process or - // if running in unit tests. - // In this case, we want to throw a more specific exception. - throw new InvalidOperationException ( - "Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", - ex - ); - } - - SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ()); - - // TODO: This is probably not needed - if (Popover.GetActivePopover () is View popover) - { - popover.Visible = false; - } - - MainThreadId = Thread.CurrentThread.ManagedThreadId; - bool init = Initialized = true; - InitializedChanged?.Invoke (null, new (init)); - } - internal static void SubscribeDriverEvents () { ArgumentNullException.ThrowIfNull (Driver); @@ -179,7 +69,10 @@ public static partial class Application // Lifecycle (Init/Shutdown) Driver.MouseEvent -= Driver_MouseEvent; } - private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { OnSizeChanging (e); } + private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) + { + RaiseScreenChangedEvent (new Rectangle (new (0, 0), e.Size!.Value)); + } private static void Driver_KeyDown (object? sender, Key e) { RaiseKeyDownEvent (e); } private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); } private static void Driver_MouseEvent (object? sender, MouseEventArgs e) { RaiseMouseEvent (e); } diff --git a/Terminal.Gui/App/Application.Run.cs b/Terminal.Gui/App/Application.Run.cs index fc6920ba9..7477325aa 100644 --- a/Terminal.Gui/App/Application.Run.cs +++ b/Terminal.Gui/App/Application.Run.cs @@ -22,10 +22,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E set => Keyboard.ArrangeKey = value; } - // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`. - // This variable is set in `End` in this case so that `Begin` correctly sets `Top`. - private static Toplevel? _cachedRunStateToplevel; - /// /// Notify that a new was created ( was called). The token is /// created in and this event will be fired before that function exits. @@ -43,7 +39,11 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E /// must also subscribe to and manually dispose of the token /// when the application is done. /// +#pragma warning disable CS0067 // Event is never used +#pragma warning disable CS0414 // Event is never used public static event EventHandler? NotifyStopRunState; +#pragma warning restore CS0414 // Event is never used +#pragma warning restore CS0067 // Event is never used /// Building block API: Prepares the provided for execution. /// @@ -74,7 +74,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E { // This assertion confirm if the Top was already disposed Debug.Assert (Top.WasDisposed); - Debug.Assert (Top == _cachedRunStateToplevel); + Debug.Assert (Top == CachedRunStateToplevel); } #endif @@ -84,7 +84,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E { // If Top was already disposed and isn't on the Toplevels Stack, // clean it up here if is the same as _cachedRunStateToplevel - if (Top == _cachedRunStateToplevel) + if (Top == CachedRunStateToplevel) { Top = null; } @@ -493,7 +493,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E Top.SetFocus (); } - _cachedRunStateToplevel = runState.Toplevel; + CachedRunStateToplevel = runState.Toplevel; runState.Toplevel = null; runState.Dispose (); diff --git a/Terminal.Gui/App/Application.Screen.cs b/Terminal.Gui/App/Application.Screen.cs index 879141412..92522c235 100644 --- a/Terminal.Gui/App/Application.Screen.cs +++ b/Terminal.Gui/App/Application.Screen.cs @@ -19,38 +19,26 @@ public static partial class Application // Screen related stuff; intended to hid } /// Invoked when the terminal's size changed. The new size of the terminal is provided. - /// - /// Event handlers can set to to prevent - /// from changing it's size to match the new terminal size. - /// - public static event EventHandler? SizeChanging; + public static event EventHandler>? ScreenChanged; /// - /// Called when the application's size changes. Sets the size of all s and fires the - /// event. + /// Called when the application's size has changed. Sets the size of all s and fires the + /// event. /// - /// The new size. - /// if the size was changed. - public static bool OnSizeChanging (SizeChangedEventArgs args) + /// The new screen size and position. + public static void RaiseScreenChangedEvent (Rectangle screen) { - SizeChanging?.Invoke (null, args); + Screen = new (Point.Empty, screen.Size); - if (args.Cancel || args.Size is null) - { - return false; - } - - Screen = new (Point.Empty, args.Size.Value); + ScreenChanged?.Invoke (ApplicationImpl.Instance, new (screen)); foreach (Toplevel t in TopLevels) { - t.OnSizeChanging (new (args.Size)); + t.OnSizeChanging (new (screen.Size)); t.SetNeedsLayout (); } LayoutAndDraw (true); - - return true; } /// diff --git a/Terminal.Gui/App/Application.Toplevel.cs b/Terminal.Gui/App/Application.Toplevel.cs index cea9818ef..eeb70522a 100644 --- a/Terminal.Gui/App/Application.Toplevel.cs +++ b/Terminal.Gui/App/Application.Toplevel.cs @@ -17,4 +17,12 @@ public static partial class Application // Toplevel handling get => ApplicationImpl.Instance.Top; internal set => ApplicationImpl.Instance.Top = value; } + + internal static Toplevel? CachedRunStateToplevel + { + get => ApplicationImpl.Instance.CachedRunStateToplevel; + private set => ApplicationImpl.Instance.CachedRunStateToplevel = value; + } + + } diff --git a/Terminal.Gui/App/Application.cs b/Terminal.Gui/App/Application.cs index 944c07918..99991bded 100644 --- a/Terminal.Gui/App/Application.cs +++ b/Terminal.Gui/App/Application.cs @@ -206,15 +206,15 @@ public static partial class Application Debug.Assert (Top.WasDisposed, $"Title = {Top.Title}, Id = {Top.Id}"); // If End wasn't called _cachedRunStateToplevel may be null - if (_cachedRunStateToplevel is { }) + if (CachedRunStateToplevel is { }) { - Debug.Assert (_cachedRunStateToplevel.WasDisposed); - Debug.Assert (_cachedRunStateToplevel == Top); + Debug.Assert (CachedRunStateToplevel.WasDisposed); + Debug.Assert (CachedRunStateToplevel == Top); } } #endif Top = null; - _cachedRunStateToplevel = null; + CachedRunStateToplevel = null; MainThreadId = -1; Iteration = null; @@ -257,7 +257,7 @@ public static partial class Application // Keyboard events and bindings are now managed by the Keyboard instance - SizeChanging = null; + ScreenChanged = null; Navigation = null; diff --git a/Terminal.Gui/App/ApplicationImpl.cs b/Terminal.Gui/App/ApplicationImpl.cs index 0eb2a35f8..e167876dd 100644 --- a/Terminal.Gui/App/ApplicationImpl.cs +++ b/Terminal.Gui/App/ApplicationImpl.cs @@ -63,11 +63,6 @@ public class ApplicationImpl : IApplication set => _mouse = value ?? throw new ArgumentNullException (nameof (value)); } - /// - /// Handles which (if any) has captured the mouse - /// - public IMouseGrabHandler MouseGrabHandler { get; set; } = new MouseGrabHandler (); - private IKeyboard? _keyboard; /// @@ -134,7 +129,7 @@ public class ApplicationImpl : IApplication } set { - if (value is {} && (value.X != 0 || value.Y != 0)) + if (value is { } && (value.X != 0 || value.Y != 0)) { throw new NotImplementedException ($"Screen locations other than 0, 0 are not yet supported"); } @@ -177,6 +172,11 @@ public class ApplicationImpl : IApplication /// public ConcurrentStack TopLevels => _topLevels; + // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`. + // This variable is set in `End` in this case so that `Begin` correctly sets `Top`. + /// + public Toplevel? CachedRunStateToplevel { get; set; } + /// /// Gets or sets the main thread ID for the application. /// @@ -231,10 +231,10 @@ public class ApplicationImpl : IApplication if (string.IsNullOrWhiteSpace (_driverName)) { - _driverName = Application.ForceDriver; + _driverName = ForceDriver; } - Debug.Assert(_navigation is null); + Debug.Assert (_navigation is null); _navigation = new (); Debug.Assert (_popover is null); @@ -264,7 +264,7 @@ public class ApplicationImpl : IApplication } CreateDriver (driverName ?? _driverName); - + Screen = Driver!.Screen; _initialized = true; Application.OnInitializedChanged (this, new (true)); @@ -276,23 +276,6 @@ public class ApplicationImpl : IApplication private void CreateDriver (string? driverName) { - // When running unit tests, always use FakeDriver unless explicitly specified - if (ConsoleDriver.RunningUnitTests && - string.IsNullOrEmpty (driverName) && - _componentFactory is null) - { - Logging.Logger.LogDebug ("Unit test safeguard: forcing FakeDriver (RunningUnitTests=true, driverName=null, componentFactory=null)"); - _coordinator = CreateSubcomponents (() => new FakeComponentFactory ()); - _coordinator.StartAsync ().Wait (); - - if (_driver == null) - { - throw new ("Driver was null even after booting MainLoopCoordinator"); - } - - return; - } - PlatformID p = Environment.OSVersion.Platform; // Check component factory type first - this takes precedence over driverName @@ -310,7 +293,10 @@ public class ApplicationImpl : IApplication // Decide which driver to use - component factory type takes priority if (factoryIsFake || (!factoryIsWindows && !factoryIsDotNet && !factoryIsUnix && nameIsFake)) { - _coordinator = CreateSubcomponents (() => new FakeComponentFactory ()); + FakeConsoleOutput fakeOutput = new (); + fakeOutput.SetConsoleSize (80, 25); + + _coordinator = CreateSubcomponents (() => new FakeComponentFactory (null, fakeOutput)); } else if (factoryIsWindows || (!factoryIsDotNet && !factoryIsUnix && nameIsWindows)) { @@ -410,7 +396,7 @@ public class ApplicationImpl : IApplication if (_driver == null) { - throw new InvalidOperationException ("Driver was inexplicably null when trying to Run view"); + throw new InvalidOperationException ("Driver was inexplicably null when trying to Run view"); } _top = view; @@ -437,17 +423,17 @@ public class ApplicationImpl : IApplication public void Shutdown () { _coordinator?.Stop (); - + bool wasInitialized = _initialized; - + // Reset Screen before calling Application.ResetState to avoid circular reference ResetScreen (); - + // Call ResetState FIRST so it can properly dispose Popover and other resources // that are accessed via Application.* static properties that now delegate to instance fields Application.ResetState (); ConfigurationManager.PrintJsonErrors (); - + // Clear instance fields after ResetState has disposed everything _driver = null; _mouse = null; @@ -455,6 +441,7 @@ public class ApplicationImpl : IApplication _initialized = false; _navigation = null; _popover = null; + CachedRunStateToplevel = null; _top = null; _topLevels.Clear (); _mainThreadId = -1; @@ -475,7 +462,7 @@ public class ApplicationImpl : IApplication /// public void RequestStop (Toplevel? top) { - Logging.Logger.LogInformation ($"RequestStop '{(top is {} ? top : "null")}'"); + Logging.Logger.LogInformation ($"RequestStop '{(top is { } ? top : "null")}'"); top ??= _top; @@ -499,7 +486,7 @@ public class ApplicationImpl : IApplication public void Invoke (Action action) { // If we are already on the main UI thread - if (Application.Top is { Running: true } && _mainThreadId == Thread.CurrentThread.ManagedThreadId) + if (Top is { Running: true } && _mainThreadId == Thread.CurrentThread.ManagedThreadId) { action (); return; diff --git a/Terminal.Gui/App/IApplication.cs b/Terminal.Gui/App/IApplication.cs index 93a4c7c22..1fb9e84f0 100644 --- a/Terminal.Gui/App/IApplication.cs +++ b/Terminal.Gui/App/IApplication.cs @@ -74,6 +74,11 @@ public interface IApplication /// Gets the stack of all Toplevels. System.Collections.Concurrent.ConcurrentStack TopLevels { get; } + /// + /// Caches the Toplevel associated with the current RunState. + /// + Toplevel? CachedRunStateToplevel { get; set; } + /// Requests that the application stop running. void RequestStop (); diff --git a/Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs b/Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs index 97aff25d6..c64ff95b4 100644 --- a/Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs +++ b/Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs @@ -27,7 +27,7 @@ public class ApplicationMainLoop : IApplicationMainLoop private IInputProcessor? _inputProcessor; private IConsoleOutput? _out; private AnsiRequestScheduler? _ansiRequestScheduler; - private IWindowSizeMonitor? _windowSizeMonitor; + private IConsoleSizeMonitor? _consoleSizeMonitor; /// public ITimedEvents TimedEvents @@ -74,10 +74,10 @@ public class ApplicationMainLoop : IApplicationMainLoop } /// - public IWindowSizeMonitor WindowSizeMonitor + public IConsoleSizeMonitor ConsoleSizeMonitor { - get => _windowSizeMonitor ?? throw new NotInitializedException (nameof (WindowSizeMonitor)); - private set => _windowSizeMonitor = value; + get => _consoleSizeMonitor ?? throw new NotInitializedException (nameof (ConsoleSizeMonitor)); + private set => _consoleSizeMonitor = value; } /// @@ -114,7 +114,7 @@ public class ApplicationMainLoop : IApplicationMainLoop TimedEvents = timedEvents; AnsiRequestScheduler = new (InputProcessor.GetParser ()); - WindowSizeMonitor = componentFactory.CreateWindowSizeMonitor (Out, OutputBuffer); + ConsoleSizeMonitor = componentFactory.CreateConsoleSizeMonitor (Out, OutputBuffer); } /// @@ -152,7 +152,7 @@ public class ApplicationMainLoop : IApplicationMainLoop || AnySubViewsNeedDrawn (Application.Top) || (Application.Mouse.MouseGrabView != null && AnySubViewsNeedDrawn (Application.Mouse.MouseGrabView)); - bool sizeChanged = WindowSizeMonitor.Poll (); + bool sizeChanged = ConsoleSizeMonitor.Poll (); if (needsDrawOrLayout || sizeChanged) { diff --git a/Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs b/Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs index eaaa95e07..f4069315e 100644 --- a/Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs +++ b/Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs @@ -48,7 +48,7 @@ public interface IApplicationMainLoop : IDisposable /// /// Gets the class responsible for determining the current console size /// - public IWindowSizeMonitor WindowSizeMonitor { get; } + public IConsoleSizeMonitor ConsoleSizeMonitor { get; } /// /// Initializes the loop with a buffer from which data can be read diff --git a/Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs b/Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs index 512a340be..60f6ced3e 100644 --- a/Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs +++ b/Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs @@ -149,7 +149,7 @@ internal class MainLoopCoordinator : IMainLoopCoordinator _loop.OutputBuffer, _output, _loop.AnsiRequestScheduler, - _loop.WindowSizeMonitor); + _loop.ConsoleSizeMonitor); Application.Driver = _facade; diff --git a/Terminal.Gui/App/Timeout/ITimedEvents.cs b/Terminal.Gui/App/Timeout/ITimedEvents.cs index 501da77bc..225301ffe 100644 --- a/Terminal.Gui/App/Timeout/ITimedEvents.cs +++ b/Terminal.Gui/App/Timeout/ITimedEvents.cs @@ -27,18 +27,6 @@ public interface ITimedEvents /// event EventHandler? Added; - /// - /// Called from to check if there are any outstanding timer handlers. - /// - /// - /// Returns the number of milliseconds remaining in the current timer (if any). Will be -1 if - /// there are no active timers. - /// - /// - /// if there is a timer active; otherwise, . - /// - bool CheckTimers (out int waitTimeout); - /// /// Removes a previously scheduled timeout. /// diff --git a/Terminal.Gui/Drawing/Ruler.cs b/Terminal.Gui/Drawing/Ruler.cs index 258ce8c12..b7e91485d 100644 --- a/Terminal.Gui/Drawing/Ruler.cs +++ b/Terminal.Gui/Drawing/Ruler.cs @@ -23,7 +23,8 @@ internal class Ruler /// Draws the . /// The location to start drawing the ruler, in screen-relative coordinates. /// The start value of the ruler. - public void Draw (Point location, int start = 0) + /// Optional Driver. If not provided, driver will be used. + public void Draw (Point location, int start = 0, IConsoleDriver? driver = null) { if (start < 0) { @@ -35,14 +36,16 @@ internal class Ruler return; } + driver ??= driver; + if (Orientation == Orientation.Horizontal) { string hrule = _hTemplate.Repeat ((int)Math.Ceiling (Length + 2 / (double)_hTemplate.Length))! [start..(Length + start)]; // Top - Application.Driver?.Move (location.X, location.Y); - Application.Driver?.AddStr (hrule); + driver?.Move (location.X, location.Y); + driver?.AddStr (hrule); } else { @@ -52,8 +55,8 @@ internal class Ruler for (int r = location.Y; r < location.Y + Length; r++) { - Application.Driver?.Move (location.X, r); - Application.Driver?.AddRune ((Rune)vrule [r - location.Y]); + driver?.Move (location.X, r); + driver?.AddRune ((Rune)vrule [r - location.Y]); } } } diff --git a/Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs b/Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs index 1d9c78cab..01df783a4 100644 --- a/Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs +++ b/Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs @@ -53,21 +53,21 @@ public class SixelSupportDetector private void TryComputeResolution (SixelSupportResult result, Action resultCallback) { - string windowSize; + string consoleSize; string sizeInChars; QueueRequest ( EscSeqUtils.CSI_RequestWindowSizeInPixels, r1 => { - windowSize = r1; + consoleSize = r1; QueueRequest ( - EscSeqUtils.CSI_ReportTerminalSizeInChars, + EscSeqUtils.CSI_ReportWindowSizeInChars, r2 => { sizeInChars = r2; - ComputeResolution (result, windowSize, sizeInChars); + ComputeResolution (result, consoleSize, sizeInChars); resultCallback (result); }, () => resultCallback (result)); @@ -75,11 +75,11 @@ public class SixelSupportDetector () => resultCallback (result)); } - private void ComputeResolution (SixelSupportResult result, string windowSize, string sizeInChars) + private void ComputeResolution (SixelSupportResult result, string consoleSize, string sizeInChars) { // Fallback to window size in pixels and characters // Example [4;600;1200t - Match pixelMatch = Regex.Match (windowSize, @"\[\d+;(\d+);(\d+)t$"); + Match pixelMatch = Regex.Match (consoleSize, @"\[\d+;(\d+);(\d+)t$"); // Example [8;30;120t Match charMatch = Regex.Match (sizeInChars, @"\[\d+;(\d+);(\d+)t$"); diff --git a/Terminal.Gui/Drawing/Thickness.cs b/Terminal.Gui/Drawing/Thickness.cs index b8690a060..72b0f6ff8 100644 --- a/Terminal.Gui/Drawing/Thickness.cs +++ b/Terminal.Gui/Drawing/Thickness.cs @@ -88,14 +88,17 @@ public record struct Thickness /// The location and size of the rectangle that bounds the thickness rectangle, in screen coordinates. /// /// The diagnostics label to draw on the bottom of the . + /// Optional driver. If not specified, will be used. /// The inner rectangle remaining to be drawn. - public Rectangle Draw (Rectangle rect, ViewDiagnosticFlags diagnosticFlags = ViewDiagnosticFlags.Off, string? label = null) + public Rectangle Draw (Rectangle rect, ViewDiagnosticFlags diagnosticFlags = ViewDiagnosticFlags.Off, string? label = null, IConsoleDriver? driver = null) { if (rect.Size.Width < 1 || rect.Size.Height < 1) { return Rectangle.Empty; } + driver ??= Application.Driver; + var clearChar = (Rune)' '; Rune leftChar = clearChar; Rune rightChar = clearChar; @@ -118,71 +121,71 @@ public record struct Thickness // Draw the Top side if (Top > 0) { - Application.Driver?.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar); + driver?.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar); } // Draw the Left side // Draw the Left side if (Left > 0) { - Application.Driver?.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar); + driver?.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar); } // Draw the Right side if (Right > 0) { - Application.Driver?.FillRect ( - rect with - { - X = Math.Max (0, rect.X + rect.Width - Right), - Width = Math.Min (rect.Width, Right) - }, - rightChar - ); + driver?.FillRect ( + rect with + { + X = Math.Max (0, rect.X + rect.Width - Right), + Width = Math.Min (rect.Width, Right) + }, + rightChar + ); } // Draw the Bottom side if (Bottom > 0) { - Application.Driver?.FillRect ( - rect with - { - Y = rect.Y + Math.Max (0, rect.Height - Bottom), - Height = Bottom - }, - bottomChar - ); + driver?.FillRect ( + rect with + { + Y = rect.Y + Math.Max (0, rect.Height - Bottom), + Height = Bottom + }, + bottomChar + ); } if (diagnosticFlags.HasFlag (ViewDiagnosticFlags.Ruler)) { // PERF: This can almost certainly be simplified down to a single point offset and fewer calls to Draw // Top - var hruler = new Ruler { Length = rect.Width, Orientation = Orientation.Horizontal }; + Ruler hRuler = new () { Length = rect.Width, Orientation = Orientation.Horizontal }; if (Top > 0) { - hruler.Draw (rect.Location); + hRuler.Draw (rect.Location, driver: driver); } //Left - var vruler = new Ruler { Length = rect.Height - 2, Orientation = Orientation.Vertical }; + Ruler vRuler = new () { Length = rect.Height - 2, Orientation = Orientation.Vertical }; if (Left > 0) { - vruler.Draw (rect.Location with { Y = rect.Y + 1 }, 1); + vRuler.Draw (rect.Location with { Y = rect.Y + 1 }, 1, driver); } // Bottom if (Bottom > 0) { - hruler.Draw (rect.Location with { Y = rect.Y + rect.Height - 1 }); + hRuler.Draw (rect.Location with { Y = rect.Y + rect.Height - 1 }, driver: driver); } // Right if (Right > 0) { - vruler.Draw (new (rect.X + rect.Width - 1, rect.Y + 1), 1); + vRuler.Draw (new (rect.X + rect.Width - 1, rect.Y + 1), 1, driver); } } @@ -191,7 +194,7 @@ public record struct Thickness // Draw the diagnostics label on the bottom string text = label is null ? string.Empty : $"{label} {this}"; - var tf = new TextFormatter + TextFormatter tf = new () { Text = text, Alignment = Alignment.Center, @@ -200,9 +203,9 @@ public record struct Thickness ConstrainToHeight = 1 }; - if (Application.Driver?.CurrentAttribute is { }) + if (driver?.CurrentAttribute is { }) { - tf.Draw (rect, Application.Driver!.CurrentAttribute, Application.Driver!.CurrentAttribute, rect); + tf.Draw (rect, driver!.CurrentAttribute, driver!.CurrentAttribute, rect, driver); } } @@ -242,7 +245,7 @@ public record struct Thickness /// public Region AsRegion (Rectangle rect) { - Region region = new Region (rect); + var region = new Region (rect); region.Exclude (GetInside (rect)); return region; diff --git a/Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs b/Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs index 97dbc933e..8e4c5e9e8 100644 --- a/Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs +++ b/Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs @@ -1,14 +1,10 @@ #nullable enable +using System.Diagnostics; using System.Globalization; -namespace Terminal.Gui.Drivers; +// ReSharper disable InconsistentNaming -// QUESTION: Should this class be refactored into separate classes for: -// QUESTION: CSI definitions -// QUESTION: Primitives like DecodeEsqReq -// QUESTION: Screen/Color/Cursor handling -// QUESTION: Mouse handling -// QUESTION: Keyboard handling +namespace Terminal.Gui.Drivers; /// /// Provides a platform-independent API for managing ANSI escape sequences. @@ -21,7 +17,18 @@ namespace Terminal.Gui.Drivers; /// public static class EscSeqUtils { - // TODO: One type per file - Move this enum to a separate file. + /// + /// Escape key code (ASCII 27/0x1B). + /// + public const char KeyEsc = (char)KeyCode.Esc; + + /// + /// ESC [ - The CSI (Control Sequence Introducer). + /// + public const string CSI = "\u001B["; + + #region Screen Window Buffer + /// /// Options for ANSI ESC "[xJ" - Clears part of the screen. /// @@ -48,19 +55,6 @@ public static class EscSeqUtils EntireScreenAndScrollbackBuffer = 3 } - // QUESTION: I wonder if EscSeqUtils.CSI_... should be more strongly typed such that this (and Terminator could be - // QUESTION: public required CSIRequests Request { get; init; } - // QUESTION: public required CSITerminators Terminator { get; init; } - /// - /// Escape key code (ASCII 27/0x1B). - /// - public const char KeyEsc = (char)KeyCode.Esc; - - /// - /// ESC [ - The CSI (Control Sequence Introducer). - /// - public const string CSI = "\u001B["; - /// /// ESC [ ? 1047 h - Activate xterm alternative buffer (no backscroll) /// @@ -71,36 +65,6 @@ public static class EscSeqUtils /// public static readonly string CSI_ActivateAltBufferNoBackscroll = CSI + "?1047h"; - /// - /// ESC [ ? 1003 l - Disable any mouse event tracking. - /// - public static readonly string CSI_DisableAnyEventMouse = CSI + "?1003l"; - - /// - /// ESC [ ? 1006 l - Disable SGR (Select Graphic Rendition). - /// - public static readonly string CSI_DisableSgrExtModeMouse = CSI + "?1006l"; - - /// - /// ESC [ ? 1015 l - Disable URXVT (Unicode Extended Virtual Terminal). - /// - public static readonly string CSI_DisableUrxvtExtModeMouse = CSI + "?1015l"; - - /// - /// ESC [ ? 1003 h - Enable mouse event tracking. - /// - public static readonly string CSI_EnableAnyEventMouse = CSI + "?1003h"; - - /// - /// ESC [ ? 1006 h - Enable SGR (Select Graphic Rendition). - /// - public static readonly string CSI_EnableSgrExtModeMouse = CSI + "?1006h"; - - /// - /// ESC [ ? 1015 h - Enable URXVT (Unicode Extended Virtual Terminal). - /// - public static readonly string CSI_EnableUrxvtExtModeMouse = CSI + "?1015h"; - /// /// ESC [ ? 1047 l - Restore xterm working buffer (with backscroll) /// @@ -135,20 +99,52 @@ public static class EscSeqUtils /// public static readonly string CSI_SaveCursorAndActivateAltBufferNoBackscroll = CSI + "?1049h"; - //private static bool isButtonReleased; - private static bool _isButtonClicked; + /// + /// ESC [ x J - Clears part of the screen. See . + /// + /// + /// + public static string CSI_ClearScreen (ClearScreenOptions option) { return $"{CSI}{(int)option}J"; } - private static bool _isButtonDoubleClicked; + /// + /// ESC [ 8 ; height ; width t - Set Terminal Window Size + /// https://terminalguide.namepad.de/seq/csi_st-8/ + /// + public static string CSI_SetTerminalWindowSize (int height, int width) { return $"{CSI}8;{height};{width}t"; } - //private static MouseFlags? lastMouseButtonReleased; - // QUESTION: What's the difference between isButtonClicked and isButtonPressed? - // Some clarity or comments would be handy, here. - // It also seems like some enforcement of valid states might be a good idea. - private static bool _isButtonPressed; - private static bool _isButtonTripleClicked; + #endregion Screen Window Buffer - private static MouseFlags? _lastMouseButtonPressed; - private static Point? _point; + #region Mouse + + /// + /// ESC [ ? 1003 l - Disable any mouse event tracking. + /// + public static readonly string CSI_DisableAnyEventMouse = CSI + "?1003l"; + + /// + /// ESC [ ? 1006 l - Disable SGR (Select Graphic Rendition). + /// + public static readonly string CSI_DisableSgrExtModeMouse = CSI + "?1006l"; + + /// + /// ESC [ ? 1015 l - Disable URXVT (Unicode Extended Virtual Terminal). + /// + public static readonly string CSI_DisableUrxvtExtModeMouse = CSI + "?1015l"; + + /// + /// ESC [ ? 1003 h - Enable mouse event tracking. + /// + public static readonly string CSI_EnableAnyEventMouse = CSI + "?1003h"; + + /// + /// ESC [ ? 1006 h - Enable SGR (Select Graphic Rendition). + /// + public static readonly string CSI_EnableSgrExtModeMouse = CSI + "?1006h"; + + /// + /// ESC [ ? 1015 h - Enable URXVT (Unicode Extended Virtual Terminal). + /// + public static readonly string CSI_EnableUrxvtExtModeMouse = CSI + "?1015h"; /// /// Control sequence for disabling mouse events. @@ -162,882 +158,16 @@ public static class EscSeqUtils public static readonly string CSI_EnableMouseEvents = CSI_EnableAnyEventMouse + CSI_EnableUrxvtExtModeMouse + CSI_EnableSgrExtModeMouse; - /// - /// ESC [ x J - Clears part of the screen. See . - /// - /// - /// - public static string CSI_ClearScreen (ClearScreenOptions option) { return $"{CSI}{(int)option}J"; } + #endregion Mouse + + #region Keyboard /// - /// Specify the incomplete array not yet recognized as valid ANSI escape sequence. - /// - public static ConsoleKeyInfo []? IncompleteCkInfos { get; set; } - - /// - /// Decodes an ANSI escape sequence. - /// - /// The which may change. - /// The which may change. - /// The array. - /// The which may change. - /// The control returned by the method. - /// The code returned by the method. - /// The values returned by the method. - /// The terminator returned by the method. - /// Indicates if the escape sequence is a mouse event. - /// The button state. - /// The position. - /// Indicates if the escape sequence is a response to a request. - /// The handler that will process the event. - public static void DecodeEscSeq ( - ref ConsoleKeyInfo newConsoleKeyInfo, - ref ConsoleKey key, - ConsoleKeyInfo [] cki, - ref ConsoleModifiers mod, - out string c1Control, - out string code, - out string [] values, - out string terminator, - out bool isMouse, - out List buttonState, - out Point pos, - out bool isResponse, - Action? continuousButtonPressedHandler - ) - { - char [] kChars = GetKeyCharArray (cki); - (c1Control, code, values, terminator) = GetEscapeResult (kChars); - isMouse = false; - buttonState = [0]; - pos = default (Point); - isResponse = false; - var keyChar = '\0'; - - switch (c1Control) - { - case "ESC": - if (values is null && string.IsNullOrEmpty (terminator)) - { - key = ConsoleKey.Escape; - - newConsoleKeyInfo = new ( - cki [0].KeyChar, - key, - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else if ((uint)cki [1].KeyChar >= 1 && (uint)cki [1].KeyChar <= 26 && (uint)cki [1].KeyChar != '\n' && (uint)cki [1].KeyChar != '\r') - { - key = (ConsoleKey)(char)(cki [1].KeyChar + (uint)ConsoleKey.A - 1); - mod = ConsoleModifiers.Alt | ConsoleModifiers.Control; - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - key, - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else if (cki [1].KeyChar >= 65 && cki [1].KeyChar <= 90) - { - key = (ConsoleKey)cki [1].KeyChar; - mod = ConsoleModifiers.Shift | ConsoleModifiers.Alt; - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - (ConsoleKey)Math.Min ((uint)key, 255), - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else if (cki [1].KeyChar >= 97 && cki [1].KeyChar <= 122) - { - key = (ConsoleKey)cki [1].KeyChar.ToString ().ToUpper () [0]; - mod = ConsoleModifiers.Alt; - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - (ConsoleKey)Math.Min ((uint)key, 255), - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else if (cki [1].KeyChar is '\0' or ' ') - { - key = ConsoleKey.Spacebar; - - if (kChars.Length > 1 && kChars [1] == '\0') - { - mod = ConsoleModifiers.Alt | ConsoleModifiers.Control; - } - else - { - mod = ConsoleModifiers.Shift | ConsoleModifiers.Alt; - } - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - (ConsoleKey)Math.Min ((uint)key, 255), - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else if (cki [1].KeyChar is '\n' or '\r') - { - key = ConsoleKey.Enter; - - if (kChars.Length > 1 && kChars [1] == '\n') - { - mod = ConsoleModifiers.Alt | ConsoleModifiers.Control; - } - else - { - mod = ConsoleModifiers.Shift | ConsoleModifiers.Alt; - } - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - (ConsoleKey)Math.Min ((uint)key, 255), - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else - { - key = (ConsoleKey)cki [1].KeyChar; - mod = ConsoleModifiers.Alt; - - newConsoleKeyInfo = new ( - cki [1].KeyChar, - (ConsoleKey)Math.Min ((uint)key, 255), - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - - break; - case "SS3": - key = GetConsoleKey (terminator [0], values [0], ref mod, ref keyChar); - - newConsoleKeyInfo = new ( - keyChar, - key, - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - - break; - case "CSI": - // Reset always IncompleteCkInfos - if (IncompleteCkInfos is { }) - { - IncompleteCkInfos = null; - } - - if (!string.IsNullOrEmpty (code) && code == "<") - { - GetMouse (cki, out buttonState, out pos, continuousButtonPressedHandler); - isMouse = true; - - return; - } - - if (EscSeqRequests.HasResponse (terminator)) - { - isResponse = true; - EscSeqRequests.Remove (terminator); - - return; - } - - if (!string.IsNullOrEmpty (terminator)) - { - System.Diagnostics.Debug.Assert (terminator.Length == 1); - - key = GetConsoleKey (terminator [0], values [0], ref mod, ref keyChar); - - if (key != 0 && values.Length > 1) - { - mod |= GetConsoleModifiers (values [1]); - } - - if (keyChar != 0 || key != 0 || mod != 0) - { - newConsoleKeyInfo = new ( - keyChar, - key, - (mod & ConsoleModifiers.Shift) != 0, - (mod & ConsoleModifiers.Alt) != 0, - (mod & ConsoleModifiers.Control) != 0); - } - else - { - // It's request response that wasn't handled by a valid request terminator - System.Diagnostics.Debug.Assert (EscSeqRequests.Statuses.Count > 0); - - isResponse = true; - EscSeqRequests.Remove (terminator); - } - } - else - { - // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/2803 - // This is caused by DotNetDriver depending on Console.KeyAvailable? - //throw new InvalidOperationException ("CSI response, but there's no terminator"); - - IncompleteCkInfos = cki; - } - - break; - default: - newConsoleKeyInfo = MapConsoleKeyInfo (cki [0]); - key = newConsoleKeyInfo.Key; - mod = newConsoleKeyInfo.Modifiers; - - break; - } - } - - /// - /// Gets the c1Control used in the called escape sequence. - /// - /// The char used. - /// The c1Control. - [Pure] - public static string GetC1ControlChar (in char c) - { - // These control characters are used in the vtXXX emulation. - return c switch - { - 'D' => "IND", // Index - 'E' => "NEL", // Next Line - 'H' => "HTS", // Tab Set - 'M' => "RI", // Reverse Index - 'N' => "SS2", // Single Shift Select of G2 Character Set: affects next character only - 'O' => "SS3", // Single Shift Select of G3 Character Set: affects next character only - 'P' => "DCS", // Device Control String - 'V' => "SPA", // Start of Guarded Area - 'W' => "EPA", // End of Guarded Area - 'X' => "SOS", // Start of String - 'Z' => "DECID", // Return Terminal ID Obsolete form of CSI c (DA) - '[' => "CSI", // Control Sequence Introducer - '\\' => "ST", // String Terminator - ']' => "OSC", // Operating System Command - '^' => "PM", // Privacy Message - '_' => "APC", // Application Program Command - _ => string.Empty - }; - } - - - /// - /// Gets the depending on terminating and value. - /// - /// - /// The terminator indicating a reply to or - /// . - /// - /// The value. - /// The which may change. - /// Normally is '\0' but on some cases may need other value. - /// The and probably the . - public static ConsoleKey GetConsoleKey (char terminator, string? value, ref ConsoleModifiers mod, ref char keyChar) - { - if (terminator == 'Z') - { - mod |= ConsoleModifiers.Shift; - } - - if (terminator == 'l') - { - keyChar = '+'; - } - - if (terminator == 'm') - { - keyChar = '-'; - } - - return (terminator, value) switch - { - ('A', _) => ConsoleKey.UpArrow, - ('B', _) => ConsoleKey.DownArrow, - ('C', _) => ConsoleKey.RightArrow, - ('D', _) => ConsoleKey.LeftArrow, - ('E', _) => ConsoleKey.Clear, - ('F', _) => ConsoleKey.End, - ('H', _) => ConsoleKey.Home, - ('P', _) => ConsoleKey.F1, - ('Q', _) => ConsoleKey.F2, - ('R', _) => ConsoleKey.F3, - ('S', _) => ConsoleKey.F4, - ('Z', _) => ConsoleKey.Tab, - ('~', "2") => ConsoleKey.Insert, - ('~', "3") => ConsoleKey.Delete, - ('~', "5") => ConsoleKey.PageUp, - ('~', "6") => ConsoleKey.PageDown, - ('~', "15") => ConsoleKey.F5, - ('~', "17") => ConsoleKey.F6, - ('~', "18") => ConsoleKey.F7, - ('~', "19") => ConsoleKey.F8, - ('~', "20") => ConsoleKey.F9, - ('~', "21") => ConsoleKey.F10, - ('~', "23") => ConsoleKey.F11, - ('~', "24") => ConsoleKey.F12, - // These terminators are used by macOS on a numeric keypad without keys modifiers - ('l', null) => ConsoleKey.Add, - ('m', null) => ConsoleKey.Subtract, - ('p', null) => ConsoleKey.Insert, - ('q', null) => ConsoleKey.End, - ('r', null) => ConsoleKey.DownArrow, - ('s', null) => ConsoleKey.PageDown, - ('t', null) => ConsoleKey.LeftArrow, - ('u', null) => ConsoleKey.Clear, - ('v', null) => ConsoleKey.RightArrow, - ('w', null) => ConsoleKey.Home, - ('x', null) => ConsoleKey.UpArrow, - ('y', null) => ConsoleKey.PageUp, - (_, _) => 0 - }; - } - - /// - /// Gets the from the value. - /// - /// The value. - /// The or zero. - public static ConsoleModifiers GetConsoleModifiers (string? value) - { - return value switch - { - "2" => ConsoleModifiers.Shift, - "3" => ConsoleModifiers.Alt, - "4" => ConsoleModifiers.Shift | ConsoleModifiers.Alt, - "5" => ConsoleModifiers.Control, - "6" => ConsoleModifiers.Shift | ConsoleModifiers.Control, - "7" => ConsoleModifiers.Alt | ConsoleModifiers.Control, - "8" => ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, - _ => 0 - }; - } -#nullable restore - - /// - /// Gets all the needed information about an escape sequence. - /// - /// The array with all chars. - /// - /// The c1Control returned by , code, values and terminating. - /// - public static (string c1Control, string code, string [] values, string terminating) GetEscapeResult (char [] kChar) - { - if (kChar is null || kChar.Length == 0 || (kChar.Length == 1 && kChar [0] != KeyEsc)) - { - return (null, null, null, null); - } - - if (kChar [0] != KeyEsc) - { - throw new InvalidOperationException ("Invalid escape character!"); - } - - if (kChar.Length == 1) - { - return ("ESC", null, null, null); - } - - if (kChar.Length == 2) - { - return ("ESC", null, null, kChar [1].ToString ()); - } - - string c1Control = GetC1ControlChar (kChar [1]); - string code = null; - int nSep = kChar.Count (static x => x == ';') + 1; - var values = new string [nSep]; - var valueIdx = 0; - var terminating = string.Empty; - - for (var i = 2; i < kChar.Length; i++) - { - char c = kChar [i]; - - if (char.IsDigit (c)) - { - // PERF: Ouch - values [valueIdx] += c.ToString (); - } - else if (c == ';') - { - valueIdx++; - } - else if (valueIdx == nSep - 1 || i == kChar.Length - 1) - { - // PERF: Ouch - terminating += c.ToString (); - } - else - { - // PERF: Ouch - code += c.ToString (); - } - } - - return (c1Control, code, values, terminating); - } - - /// - /// A helper to get only the from the array. - /// - /// - /// The char array of the escape sequence. - // PERF: This is expensive - public static char [] GetKeyCharArray (ConsoleKeyInfo [] cki) - { - char [] kChar = []; - var length = 0; - - foreach (ConsoleKeyInfo kc in cki) - { - length++; - Array.Resize (ref kChar, length); - kChar [length - 1] = kc.KeyChar; - } - - return kChar; - } - - /// - /// Gets the mouse button flags and the position. - /// - /// The array. - /// The mouse button flags. - /// The mouse position. - /// The handler that will process the event. - public static void GetMouse ( - ConsoleKeyInfo [] cki, - out List mouseFlags, - out Point pos, - Action continuousButtonPressedHandler - ) - { - MouseFlags buttonState = 0; - pos = Point.Empty; - var buttonCode = 0; - var foundButtonCode = false; - var foundPoint = 0; - string value = string.Empty; - char [] kChar = GetKeyCharArray (cki); - - // PERF: This loop could benefit from use of Spans and other strategies to avoid copies. - //System.Diagnostics.Debug.WriteLine ($"kChar: {new string (kChar)}"); - for (var i = 0; i < kChar.Length; i++) - { - // PERF: Copy - char c = kChar [i]; - - if (c == '<') - { - foundButtonCode = true; - } - else if (foundButtonCode && c != ';') - { - // PERF: Ouch - value += c.ToString (); - } - else if (c == ';') - { - if (foundButtonCode) - { - foundButtonCode = false; - buttonCode = int.Parse (value); - } - - if (foundPoint == 1) - { - pos.X = int.Parse (value) - 1; - } - - value = string.Empty; - foundPoint++; - } - else if (foundPoint > 0 && c != 'm' && c != 'M') - { - value += c.ToString (); - } - else if (c == 'm' || c == 'M') - { - //pos.Y = int.Parse (value) + Console.WindowTop - 1; - pos.Y = int.Parse (value) - 1; - - switch (buttonCode) - { - case 0: - case 8: - case 16: - case 24: - case 32: - case 36: - case 40: - case 48: - case 56: - buttonState = c == 'M' - ? MouseFlags.Button1Pressed - : MouseFlags.Button1Released; - - break; - case 1: - case 9: - case 17: - case 25: - case 33: - case 37: - case 41: - case 45: - case 49: - case 53: - case 57: - case 61: - buttonState = c == 'M' - ? MouseFlags.Button2Pressed - : MouseFlags.Button2Released; - - break; - case 2: - case 10: - case 14: - case 18: - case 22: - case 26: - case 30: - case 34: - case 42: - case 46: - case 50: - case 54: - case 58: - case 62: - buttonState = c == 'M' - ? MouseFlags.Button3Pressed - : MouseFlags.Button3Released; - - break; - case 35: - //// Needed for Windows OS - //if (isButtonPressed && c == 'm' - // && (lastMouseEvent.ButtonState == MouseFlags.Button1Pressed - // || lastMouseEvent.ButtonState == MouseFlags.Button2Pressed - // || lastMouseEvent.ButtonState == MouseFlags.Button3Pressed)) { - - // switch (lastMouseEvent.ButtonState) { - // case MouseFlags.Button1Pressed: - // buttonState = MouseFlags.Button1Released; - // break; - // case MouseFlags.Button2Pressed: - // buttonState = MouseFlags.Button2Released; - // break; - // case MouseFlags.Button3Pressed: - // buttonState = MouseFlags.Button3Released; - // break; - // } - //} else { - // buttonState = MouseFlags.ReportMousePosition; - //} - //break; - case 39: - case 43: - case 47: - case 51: - case 55: - case 59: - case 63: - buttonState = MouseFlags.ReportMousePosition; - - break; - case 64: - buttonState = MouseFlags.WheeledUp; - - break; - case 65: - buttonState = MouseFlags.WheeledDown; - - break; - case 68: - case 72: - case 80: - buttonState = MouseFlags.WheeledLeft; // Shift/Ctrl+WheeledUp - - break; - case 69: - case 73: - case 81: - buttonState = MouseFlags.WheeledRight; // Shift/Ctrl+WheeledDown - - break; - } - - // Modifiers. - switch (buttonCode) - { - case 8: - case 9: - case 10: - case 43: - buttonState |= MouseFlags.ButtonAlt; - - break; - case 14: - case 47: - buttonState |= MouseFlags.ButtonAlt | MouseFlags.ButtonShift; - - break; - case 16: - case 17: - case 18: - case 51: - buttonState |= MouseFlags.ButtonCtrl; - - break; - case 22: - case 55: - buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift; - - break; - case 24: - case 25: - case 26: - case 59: - buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt; - - break; - case 30: - case 63: - buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt; - - break; - case 32: - case 33: - case 34: - buttonState |= MouseFlags.ReportMousePosition; - - break; - case 36: - case 37: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonShift; - - break; - case 39: - case 68: - case 69: - buttonState |= MouseFlags.ButtonShift; - - break; - case 40: - case 41: - case 42: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt; - - break; - case 45: - case 46: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt | MouseFlags.ButtonShift; - - break; - case 48: - case 49: - case 50: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl; - - break; - case 53: - case 54: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift; - - break; - case 56: - case 57: - case 58: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt; - - break; - case 61: - case 62: - buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt; - - break; - } - } - } - - mouseFlags = [MouseFlags.AllEvents]; - - if (_lastMouseButtonPressed != null - && !_isButtonPressed - && !buttonState.HasFlag (MouseFlags.ReportMousePosition) - && !buttonState.HasFlag (MouseFlags.Button1Released) - && !buttonState.HasFlag (MouseFlags.Button2Released) - && !buttonState.HasFlag (MouseFlags.Button3Released) - && !buttonState.HasFlag (MouseFlags.Button4Released)) - { - _lastMouseButtonPressed = null; - _isButtonPressed = false; - } - - if ((!_isButtonClicked - && !_isButtonDoubleClicked - && (buttonState == MouseFlags.Button1Pressed - || buttonState == MouseFlags.Button2Pressed - || buttonState == MouseFlags.Button3Pressed - || buttonState == MouseFlags.Button4Pressed) - && _lastMouseButtonPressed is null) - || (_isButtonPressed && _lastMouseButtonPressed is { } && buttonState.HasFlag (MouseFlags.ReportMousePosition))) - { - mouseFlags [0] = buttonState; - _lastMouseButtonPressed = buttonState; - _isButtonPressed = true; - - _point = pos; - - - if (mouseFlags [0].HasFlag (MouseFlags.ReportMousePosition)) - { - _point = pos; - - // The isButtonPressed must always be true, otherwise we can lose the feature - // If mouse flags has ReportMousePosition this feature won't run - // but is always prepared with the new location - //isButtonPressed = false; - } - } - else if (_isButtonDoubleClicked - && (buttonState == MouseFlags.Button1Pressed - || buttonState == MouseFlags.Button2Pressed - || buttonState == MouseFlags.Button3Pressed - || buttonState == MouseFlags.Button4Pressed)) - { - mouseFlags [0] = GetButtonTripleClicked (buttonState); - _isButtonDoubleClicked = false; - _isButtonTripleClicked = true; - } - else if (_isButtonClicked - && (buttonState == MouseFlags.Button1Pressed - || buttonState == MouseFlags.Button2Pressed - || buttonState == MouseFlags.Button3Pressed - || buttonState == MouseFlags.Button4Pressed)) - { - mouseFlags [0] = GetButtonDoubleClicked (buttonState); - _isButtonClicked = false; - _isButtonDoubleClicked = true; - - ApplicationImpl.Instance.TimedEvents?.Add (TimeSpan.Zero, - () => - { - Task.Run (async () => await ProcessButtonDoubleClickedAsync ()); - - return false; - }); - } - - //else if (isButtonReleased && !isButtonClicked && buttonState == MouseFlags.ReportMousePosition) { - // mouseFlag [0] = GetButtonClicked ((MouseFlags)lastMouseButtonReleased); - // lastMouseButtonReleased = null; - // isButtonReleased = false; - // isButtonClicked = true; - // Application.MainLoop.AddTimeout (() => { - // Task.Run (async () => await ProcessButtonClickedAsync ()); - // return false; - // }); - - //} - else if (!_isButtonClicked - && !_isButtonDoubleClicked - && (buttonState == MouseFlags.Button1Released - || buttonState == MouseFlags.Button2Released - || buttonState == MouseFlags.Button3Released - || buttonState == MouseFlags.Button4Released)) - { - mouseFlags [0] = buttonState; - _isButtonPressed = false; - - if (_isButtonTripleClicked) - { - _isButtonTripleClicked = false; - } - else if (pos.X == _point?.X && pos.Y == _point?.Y) - { - mouseFlags.Add (GetButtonClicked (buttonState)); - _isButtonClicked = true; - - ApplicationImpl.Instance.TimedEvents?.Add (TimeSpan.Zero, - () => - { - Task.Run (async () => await ProcessButtonClickedAsync ()); - - return false; - }); - } - - _point = pos; - - //if ((lastMouseButtonPressed & MouseFlags.ReportMousePosition) == 0) { - // lastMouseButtonReleased = buttonState; - // isButtonPressed = false; - // isButtonReleased = true; - //} else { - // lastMouseButtonPressed = null; - // isButtonPressed = false; - //} - } - else if (buttonState == MouseFlags.WheeledUp) - { - mouseFlags [0] = MouseFlags.WheeledUp; - } - else if (buttonState == MouseFlags.WheeledDown) - { - mouseFlags [0] = MouseFlags.WheeledDown; - } - else if (buttonState == MouseFlags.WheeledLeft) - { - mouseFlags [0] = MouseFlags.WheeledLeft; - } - else if (buttonState == MouseFlags.WheeledRight) - { - mouseFlags [0] = MouseFlags.WheeledRight; - } - else if (buttonState == MouseFlags.ReportMousePosition) - { - mouseFlags [0] = MouseFlags.ReportMousePosition; - } - else - { - mouseFlags [0] = buttonState; - - //foreach (var flag in buttonState.GetUniqueFlags()) { - // mouseFlag [0] |= flag; - //} - } - - mouseFlags [0] = SetControlKeyStates (buttonState, mouseFlags [0]); - - //buttonState = mouseFlags; - - //System.Diagnostics.Debug.WriteLine ($"buttonState: {buttonState} X: {pos.X} Y: {pos.Y}"); - //foreach (var mf in mouseFlags) { - // System.Diagnostics.Debug.WriteLine ($"mouseFlags: {mf} X: {pos.X} Y: {pos.Y}"); - //} - } - - /// - /// Helper to set the Control key states based on the char. + /// Helper to set the Control key states based on the char. /// /// The char value. /// - public static ConsoleKeyInfo MapChar (char ch) - { - return MapConsoleKeyInfo (new (ch, ConsoleKey.None, false, false, false)); - } + public static ConsoleKeyInfo MapChar (char ch) { return MapConsoleKeyInfo (new (ch, ConsoleKey.None, false, false, false)); } /// /// Ensures a console key is mapped to one that works correctly with ANSI escape sequences. @@ -1047,7 +177,7 @@ public static class EscSeqUtils public static ConsoleKeyInfo MapConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) { ConsoleKeyInfo newConsoleKeyInfo = consoleKeyInfo; - ConsoleKey key = ConsoleKey.None; + var key = ConsoleKey.None; char keyChar = consoleKeyInfo.KeyChar; switch ((uint)keyChar) @@ -1142,7 +272,7 @@ public static class EscSeqUtils } break; - case uint n when n is >= '\u001c' and <= '\u001f': + case uint n when n is >= '\u001c' and <= '\u001f': key = (ConsoleKey)(char)(consoleKeyInfo.KeyChar + 24); newConsoleKeyInfo = new ( @@ -1195,203 +325,6 @@ public static class EscSeqUtils } } - private static MouseFlags _lastMouseFlags; - - /// - /// Provides a handler to be invoked when mouse continuous button pressed is processed. - /// - public static event EventHandler ContinuousButtonPressed; - - /// - /// Provides a default mouse event handler that can be used by any driver. - /// - /// The mouse flags event. - /// The mouse position. - public static void ProcessMouseEvent (MouseFlags mouseFlag, Point pos) - { - bool WasButtonReleased (MouseFlags flag) - { - return flag.HasFlag (MouseFlags.Button1Released) - || flag.HasFlag (MouseFlags.Button2Released) - || flag.HasFlag (MouseFlags.Button3Released) - || flag.HasFlag (MouseFlags.Button4Released); - } - - bool IsButtonNotPressed (MouseFlags flag) - { - return !flag.HasFlag (MouseFlags.Button1Pressed) - && !flag.HasFlag (MouseFlags.Button2Pressed) - && !flag.HasFlag (MouseFlags.Button3Pressed) - && !flag.HasFlag (MouseFlags.Button4Pressed); - } - - bool IsButtonClickedOrDoubleClicked (MouseFlags flag) - { - return flag.HasFlag (MouseFlags.Button1Clicked) - || flag.HasFlag (MouseFlags.Button2Clicked) - || flag.HasFlag (MouseFlags.Button3Clicked) - || flag.HasFlag (MouseFlags.Button4Clicked) - || flag.HasFlag (MouseFlags.Button1DoubleClicked) - || flag.HasFlag (MouseFlags.Button2DoubleClicked) - || flag.HasFlag (MouseFlags.Button3DoubleClicked) - || flag.HasFlag (MouseFlags.Button4DoubleClicked); - } - - if ((WasButtonReleased (mouseFlag) && IsButtonNotPressed (_lastMouseFlags)) || (IsButtonClickedOrDoubleClicked (mouseFlag) && _lastMouseFlags == 0)) - { - return; - } - - _lastMouseFlags = mouseFlag; - - var me = new MouseEventArgs { Flags = mouseFlag, Position = pos }; - - ContinuousButtonPressed?.Invoke ((mouseFlag, pos), me); - } - - /// - /// A helper to resize the as needed. - /// - /// The . - /// The array to resize. - /// The resized. - public static ConsoleKeyInfo [] ResizeArray (ConsoleKeyInfo consoleKeyInfo, ConsoleKeyInfo [] cki) - { - Array.Resize (ref cki, cki is null ? 1 : cki.Length + 1); - cki [^1] = consoleKeyInfo; - - return cki; - } - - /// - /// Insert a array into the another array at the specified - /// index. - /// - /// The array to insert. - /// The array where will be added the array. - /// The start index to insert the array, default is 0. - /// The array with another array inserted. - public static ConsoleKeyInfo [] InsertArray ([CanBeNull] ConsoleKeyInfo [] toInsert, ConsoleKeyInfo [] cki, int index = 0) - { - if (toInsert is null) - { - return cki; - } - - if (cki is null) - { - return toInsert; - } - - if (index < 0) - { - index = 0; - } - - ConsoleKeyInfo [] backupCki = cki.Clone () as ConsoleKeyInfo []; - - Array.Resize (ref cki, cki.Length + toInsert.Length); - - for (var i = 0; i < cki.Length; i++) - { - if (i == index) - { - for (var j = 0; j < toInsert.Length; j++) - { - cki [i] = toInsert [j]; - i++; - } - - for (int k = index; k < backupCki!.Length; k++) - { - cki [i] = backupCki [k]; - i++; - } - } - else - { - cki [i] = backupCki! [i]; - } - } - - return cki; - } - - private static MouseFlags GetButtonClicked (MouseFlags mouseFlag) - { - MouseFlags mf = default; - - switch (mouseFlag) - { - case MouseFlags.Button1Released: - mf = MouseFlags.Button1Clicked; - - break; - - case MouseFlags.Button2Released: - mf = MouseFlags.Button2Clicked; - - break; - - case MouseFlags.Button3Released: - mf = MouseFlags.Button3Clicked; - - break; - } - - return mf; - } - - private static MouseFlags GetButtonDoubleClicked (MouseFlags mouseFlag) - { - MouseFlags mf = default; - - switch (mouseFlag) - { - case MouseFlags.Button1Pressed: - mf = MouseFlags.Button1DoubleClicked; - - break; - - case MouseFlags.Button2Pressed: - mf = MouseFlags.Button2DoubleClicked; - - break; - - case MouseFlags.Button3Pressed: - mf = MouseFlags.Button3DoubleClicked; - - break; - } - - return mf; - } - - private static MouseFlags GetButtonTripleClicked (MouseFlags mouseFlag) - { - MouseFlags mf = default; - - switch (mouseFlag) - { - case MouseFlags.Button1Pressed: - mf = MouseFlags.Button1TripleClicked; - - break; - - case MouseFlags.Button2Pressed: - mf = MouseFlags.Button2TripleClicked; - - break; - - case MouseFlags.Button3Pressed: - mf = MouseFlags.Button3TripleClicked; - - break; - } - - return mf; - } - internal static KeyCode MapKey (ConsoleKeyInfo keyInfo) { switch (keyInfo.Key) @@ -1441,7 +374,7 @@ public static class EscSeqUtils && keyInfo.Key != ConsoleKey.Oem102) { // If the keyChar is 0, keyInfo.Key value is not a printable character. - System.Diagnostics.Debug.Assert (keyInfo.Key == 0); + Debug.Assert (keyInfo.Key == 0); } return KeyCode.Null; // MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode)keyInfo.Key); @@ -1522,143 +455,7 @@ public static class EscSeqUtils return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar); } - private static async Task ProcessButtonClickedAsync () - { - await Task.Delay (300); - _isButtonClicked = false; - } - - private static async Task ProcessButtonDoubleClickedAsync () - { - await Task.Delay (300); - _isButtonDoubleClicked = false; - } - - private static MouseFlags SetControlKeyStates (MouseFlags buttonState, MouseFlags mouseFlag) - { - if ((buttonState & MouseFlags.ButtonCtrl) != 0 && (mouseFlag & MouseFlags.ButtonCtrl) == 0) - { - mouseFlag |= MouseFlags.ButtonCtrl; - } - - if ((buttonState & MouseFlags.ButtonShift) != 0 && (mouseFlag & MouseFlags.ButtonShift) == 0) - { - mouseFlag |= MouseFlags.ButtonShift; - } - - if ((buttonState & MouseFlags.ButtonAlt) != 0 && (mouseFlag & MouseFlags.ButtonAlt) == 0) - { - mouseFlag |= MouseFlags.ButtonAlt; - } - - return mouseFlag; - } - - /// - /// Split a raw string into a list of string with the correct ansi escape sequence. - /// - /// The raw string containing one or many ansi escape sequence. - /// A list with a valid ansi escape sequence. - public static List SplitEscapeRawString (string rawData) - { - List splitList = []; - var isEscSeq = false; - var split = string.Empty; - char previousChar = '\0'; - - for (var i = 0; i < rawData.Length; i++) - { - char c = rawData [i]; - - if (c == '\u001B') - { - isEscSeq = true; - - split = AddAndClearSplit (); - - split += c.ToString (); - } - else if (!isEscSeq && c >= Key.Space) - { - split = AddAndClearSplit (); - splitList.Add (c.ToString ()); - } - else if ((previousChar != '\u001B' && c <= Key.Space) || (previousChar != '\u001B' && c == 127) - || (char.IsLetter (previousChar) && char.IsLower (c) && char.IsLetter (c)) - || (!string.IsNullOrEmpty (split) && split.Length > 2 && char.IsLetter (previousChar) && char.IsLetterOrDigit (c)) - || (!string.IsNullOrEmpty (split) && split.Length > 2 && char.IsLetter (previousChar) && char.IsPunctuation (c)) - || (!string.IsNullOrEmpty (split) && split.Length > 2 && char.IsLetter (previousChar) && char.IsSymbol (c))) - { - isEscSeq = false; - split = AddAndClearSplit (); - splitList.Add (c.ToString ()); - } - else - { - split += c.ToString (); - } - - if (!string.IsNullOrEmpty (split) && i == rawData.Length - 1) - { - splitList.Add (split); - } - - previousChar = c; - } - - return splitList; - - string AddAndClearSplit () - { - if (!string.IsNullOrEmpty (split)) - { - splitList.Add (split); - split = string.Empty; - } - - return split; - } - } - - /// - /// Convert a array to string. - /// - /// - /// The string representing the array. - public static string ToString (ConsoleKeyInfo [] consoleKeyInfos) - { - StringBuilder sb = new (); - - foreach (ConsoleKeyInfo keyChar in consoleKeyInfos) - { - sb.Append (keyChar.KeyChar); - } - - return sb.ToString (); - } - - /// - /// Convert a string to array. - /// - /// - /// The representing the string. - public static ConsoleKeyInfo [] ToConsoleKeyInfoArray (string ansi) - { - if (ansi is null) - { - return null; - } - - ConsoleKeyInfo [] cki = new ConsoleKeyInfo [ansi.Length]; - - for (var i = 0; i < ansi.Length; i++) - { - char c = ansi [i]; - cki [i] = new (c, 0, false, false, false); - } - - return cki; - } + #endregion Keyboard #region Cursor @@ -1674,12 +471,6 @@ public static class EscSeqUtils /// public static readonly string CSI_RestoreCursorPosition = CSI + "8"; - /// - /// ESC [ 8 ; height ; width t - Set Terminal Window Size - /// https://terminalguide.namepad.de/seq/csi_st-8/ - /// - public static string CSI_SetTerminalWindowSize (int height, int width) { return $"{CSI}8;{height};{width}t"; } - //ESC [ < n > A - CUU - Cursor Up Cursor up by < n > //ESC [ < n > B - CUD - Cursor Down Cursor down by < n > //ESC [ < n > C - CUF - Cursor Forward Cursor forward (Right) by < n > @@ -1721,19 +512,25 @@ public static class EscSeqUtils public static void CSI_WriteCursorPosition (TextWriter writer, int row, int col) { const int maxInputBufferSize = + // CSI (2) + ';' + 'H' - 4 + + 4 + + + // row + col (2x int sign + int max value) - 2 + 20; - Span buffer = stackalloc char[maxInputBufferSize]; + 2 + + 20; + Span buffer = stackalloc char [maxInputBufferSize]; + if (!buffer.TryWrite (CultureInfo.InvariantCulture, $"{CSI}{row};{col}H", out int charsWritten)) { - string tooLongCursorPositionSequence = $"{CSI}{row};{col}H"; + var tooLongCursorPositionSequence = $"{CSI}{row};{col}H"; + throw new InvalidOperationException ( - $"{nameof(CSI_WriteCursorPosition)} buffer (len: {buffer.Length}) is too short for cursor position sequence '{tooLongCursorPositionSequence}' (len: {tooLongCursorPositionSequence.Length})."); + $"{nameof (CSI_WriteCursorPosition)} buffer (len: {buffer.Length}) is too short for cursor position sequence '{tooLongCursorPositionSequence}' (len: {tooLongCursorPositionSequence.Length})."); } - ReadOnlySpan cursorPositionSequence = buffer[..charsWritten]; + ReadOnlySpan cursorPositionSequence = buffer [..charsWritten]; writer.Write (cursorPositionSequence); } @@ -1806,7 +603,7 @@ public static class EscSeqUtils /// public static string CSI_SetCursorStyle (DECSCUSR_Style style) { return $"{CSI}{(int)style} q"; } - #endregion + #endregion Cursor #region Colors @@ -1870,25 +667,27 @@ public static class EscSeqUtils builder.Append ($"{CSI}48;2;{r};{g};{b}m"); } - - - #endregion + #endregion Colors #region Text Styles /// - /// Appends an ANSI SGR (Select Graphic Rendition) escape sequence to switch printed text from one to another. + /// Appends an ANSI SGR (Select Graphic Rendition) escape sequence to switch printed text from one + /// to another. /// /// to add escape sequence to. /// Previous to change away from. /// Next to change to. /// - /// - /// Unlike colors, most text styling options are not mutually exclusive with each other, and can be applied independently. This creates a problem when - /// switching from one style to another: For instance, if your previous style is just bold, and your next style is just italic, then simply adding the - /// sequence to enable italic text would cause the text to remain bold. This method automatically handles this problem, enabling and disabling styles as - /// necessary to apply exactly the next style. - /// + /// + /// Unlike colors, most text styling options are not mutually exclusive with each other, and can be applied + /// independently. This creates a problem when + /// switching from one style to another: For instance, if your previous style is just bold, and your next style is + /// just italic, then simply adding the + /// sequence to enable italic text would cause the text to remain bold. This method automatically handles this + /// problem, enabling and disabling styles as + /// necessary to apply exactly the next style. + /// /// internal static void CSI_AppendTextStyleChange (StringBuilder output, TextStyle prev, TextStyle next) { @@ -1901,12 +700,12 @@ public static class EscSeqUtils // Bitwise operations to determine flag changes. A ^ B are the flags different between two flag sets. These different flags that exist in the next flag // set (diff & next) are the ones that were enabled in the switch, those that exist in the previous flag set (diff & prev) are the ones that were // disabled. - var diff = prev ^ next; - var enabled = diff & next; - var disabled = diff & prev; + TextStyle diff = prev ^ next; + TextStyle enabled = diff & next; + TextStyle disabled = diff & prev; // List of escape codes to apply. - var sgr = new List (); + List sgr = new (); if (disabled != TextStyle.None) { @@ -2059,25 +858,24 @@ public static class EscSeqUtils /// /// CSI 1 8 t | yes | yes | yes | report window size in chars /// https://terminalguide.namepad.de/seq/csi_st-18/ - /// The terminator indicating a reply to : ESC [ 8 ; height ; width t + /// The terminator indicating a reply to : ESC [ 8 ; height ; width t /// - public static readonly AnsiEscapeSequence CSI_ReportTerminalSizeInChars = new () { Request = CSI + "18t", Terminator = "t", Value = "8" }; - + public static readonly AnsiEscapeSequence CSI_ReportWindowSizeInChars = new () { Request = CSI + "18t", Terminator = "t", Value = "8" }; /// - /// The terminator indicating a reply to : ESC [ 8 ; height ; width t + /// The terminator indicating a reply to : ESC [ 8 ; height ; width t /// - public const string CSI_ReportTerminalSizeInChars_Terminator = "t"; + public const string CSI_ReportWindowSizeInChars_Terminator = "t"; /// - /// The value of the response to indicating value 1 and 2 are the terminal + /// The value of the response to indicating value 1 and 2 are the terminal /// size in chars. /// - public const string CSI_ReportTerminalSizeInChars_ResponseValue = "8"; + public const string CSI_ReportWindowSizeInChars_ResponseValue = "8"; - #endregion + #endregion Requests - #region OSC 8 Hyperlinks + #region OSC /// /// OSC (Operating System Command) escape sequence prefix. @@ -2112,6 +910,7 @@ public static class EscSeqUtils // Format: ESC ] 8 ; params ; URL ST // params can include "id=value" for matching start/end string parameters = string.IsNullOrEmpty (id) ? "" : $"id={id}"; + return $"{OSC}8;{parameters};{url}{ST}"; } @@ -2129,5 +928,22 @@ public static class EscSeqUtils return $"{OSC}8;;{ST}"; } - #endregion + #endregion OSC + + /// + /// Convert a array to string. + /// + /// + /// The string representing the array. + public static string ToString (ConsoleKeyInfo [] consoleKeyInfos) + { + StringBuilder sb = new (); + + foreach (ConsoleKeyInfo keyChar in consoleKeyInfos) + { + sb.Append (keyChar.KeyChar); + } + + return sb.ToString (); + } } diff --git a/Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs b/Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs index 6e030e9bd..7a3e41a6d 100644 --- a/Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs +++ b/Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs @@ -33,7 +33,7 @@ internal static class Osc8UrlLinker internal static StringBuilder WrapOsc8 (StringBuilder input, Options options) { - if (input is null || input.Length == 0) + if (input.Length == 0) { return input; } diff --git a/Terminal.Gui/Drivers/ComponentFactory.cs b/Terminal.Gui/Drivers/ComponentFactory.cs index 3c5adddd2..3a80fd2e6 100644 --- a/Terminal.Gui/Drivers/ComponentFactory.cs +++ b/Terminal.Gui/Drivers/ComponentFactory.cs @@ -16,9 +16,9 @@ public abstract class ComponentFactory : IComponentFactory public abstract IInputProcessor CreateInputProcessor (ConcurrentQueue inputBuffer); /// - public virtual IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) + public virtual IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { - return new WindowSizeMonitor (consoleOutput, outputBuffer); + return new ConsoleSizeMonitor (consoleOutput, outputBuffer); } /// diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index 534adefb7..a4c668f74 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -60,6 +60,19 @@ public abstract class ConsoleDriver : IConsoleDriver /// Gets the location and size of the terminal screen. public Rectangle Screen => new (0, 0, Cols, Rows); + /// + /// Sets the screen size for testing purposes. Only supported by FakeDriver. + /// is the source of truth for screen dimensions. + /// and are read-only and derived from . + /// + /// The new width in columns. + /// The new height in rows. + /// Thrown when called on non-FakeDriver instances. + public virtual void SetScreenSize (int width, int height) + { + throw new NotSupportedException ("SetScreenSize is only supported by FakeDriver for test scenarios."); + } + private Region? _clip; /// @@ -508,9 +521,17 @@ public abstract class ConsoleDriver : IConsoleDriver } } - /// Called when the terminal size changes. Fires the event. - /// - public void OnSizeChanged (SizeChangedEventArgs args) { SizeChanged?.Invoke (this, args); } + /// + /// Called when the terminal screen changes (size, position, etc.). Fires the event. + /// reflects the source of truth for screen dimensions. + /// and are derived from and are read-only. + /// + /// Event arguments containing the new screen size. + public void OnSizeChanged (SizeChangedEventArgs args) + { + SizeChanged?.Invoke (this, args); + } + /// Updates the screen to reflect all the changes that have been done to the display buffer public void Refresh () @@ -531,13 +552,17 @@ public abstract class ConsoleDriver : IConsoleDriver /// upon success public abstract bool SetCursorVisibility (CursorVisibility visibility); - /// The event fired when the terminal is resized. + /// + /// The event fired when the screen changes (size, position, etc.). + /// is the source of truth for screen dimensions. + /// and are read-only and derived from . + /// public event EventHandler? SizeChanged; #endregion Cursor Handling /// Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver. - /// This is only implemented in . + /// This is only implemented in the Unix driver. public abstract void Suspend (); /// Sets the position of the terminal cursor to and . @@ -603,20 +628,7 @@ public abstract class ConsoleDriver : IConsoleDriver /// Gets the current . /// The current attribute. public Attribute GetAttribute () { return CurrentAttribute; } - - /// Makes an . - /// The foreground color. - /// The background color. - /// The attribute for the foreground and background colors. - public virtual Attribute MakeColor (in Color foreground, in Color background) - { - // Encode the colors into the int value. - return new ( - foreground, - background - ); - } - + #endregion Color Handling #region Mouse Handling diff --git a/Terminal.Gui/Drivers/ConsoleDriverFacade.cs b/Terminal.Gui/Drivers/ConsoleDriverFacade.cs index ef12ec04e..cc7a1c118 100644 --- a/Terminal.Gui/Drivers/ConsoleDriverFacade.cs +++ b/Terminal.Gui/Drivers/ConsoleDriverFacade.cs @@ -10,13 +10,15 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade private readonly AnsiRequestScheduler _ansiRequestScheduler; private CursorVisibility _lastCursor = CursorVisibility.Default; - /// The event fired when the terminal is resized. + /// + /// The event fired when the screen changes (size, position, etc.). + /// public event EventHandler? SizeChanged; public IInputProcessor InputProcessor { get; } public IOutputBuffer OutputBuffer => _outputBuffer; - public IWindowSizeMonitor WindowSizeMonitor { get; } + public IConsoleSizeMonitor ConsoleSizeMonitor { get; } public ConsoleDriverFacade ( @@ -24,7 +26,7 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade IOutputBuffer outputBuffer, IConsoleOutput output, AnsiRequestScheduler ansiRequestScheduler, - IWindowSizeMonitor windowSizeMonitor + IConsoleSizeMonitor sizeMonitor ) { InputProcessor = inputProcessor; @@ -40,8 +42,12 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade MouseEvent?.Invoke (s, e); }; - WindowSizeMonitor = windowSizeMonitor; - windowSizeMonitor.SizeChanging += (_,e) => SizeChanged?.Invoke (this, e); + ConsoleSizeMonitor = sizeMonitor; + sizeMonitor.SizeChanged += (_, e) => + { + SetScreenSize(e.Size!.Value.Width, e.Size.Value.Height); + //SizeChanged?.Invoke (this, e); + }; CreateClipboard (); } @@ -50,7 +56,7 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade { if (FakeDriver.FakeBehaviors.UseFakeClipboard) { - Clipboard = new FakeDriver.FakeClipboard ( + Clipboard = new FakeClipboard ( FakeDriver.FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException, FakeDriver.FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse); @@ -73,7 +79,7 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade } else { - Clipboard = new FakeDriver.FakeClipboard (); + Clipboard = new FakeClipboard (); } } @@ -88,10 +94,23 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade return Rectangle.Empty; } - return new (new (0, 0), _output.GetWindowSize ()); + return new (0, 0, _outputBuffer.Cols, _outputBuffer.Rows); } } + /// + /// Sets the screen size for testing purposes. Only supported by FakeDriver. + /// + /// The new width in columns. + /// The new height in rows. + /// Thrown when called on non-FakeDriver instances. + public virtual void SetScreenSize (int width, int height) + { + _outputBuffer.SetSize (width, height); + _output.SetSize (width, height); + SizeChanged?.Invoke(this, new (new (width, height))); + } + /// /// Gets or sets the clip rectangle that and are subject /// to. @@ -104,7 +123,7 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade } /// Get the operating system clipboard. - public IClipboard Clipboard { get; private set; } = new FakeDriver.FakeClipboard (); + public IClipboard Clipboard { get; private set; } = new FakeClipboard (); /// /// Gets the column last set by . and are used by @@ -364,7 +383,6 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade public void UpdateCursor () { _output.SetCursorPosition (Col, Row); } /// Initializes the driver - /// Returns an instance of using the for the driver. public void Init () { throw new NotSupportedException (); } /// Ends the execution of the console driver. @@ -375,26 +393,20 @@ internal class ConsoleDriverFacade : IConsoleDriver, IConsoleDriverFacade /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString. /// Implementations should call base.SetAttribute(c). - /// C. - public Attribute SetAttribute (Attribute c) { return _outputBuffer.CurrentAttribute = c; } + /// C. + /// The previously set Attribute. + public Attribute SetAttribute (Attribute newAttribute) + { + Attribute currentAttribute = _outputBuffer.CurrentAttribute; + _outputBuffer.CurrentAttribute = newAttribute; + + return currentAttribute; + } /// Gets the current . /// The current attribute. public Attribute GetAttribute () { return _outputBuffer.CurrentAttribute; } - /// Makes an . - /// The foreground color. - /// The background color. - /// The attribute for the foreground and background colors. - public Attribute MakeColor (in Color foreground, in Color background) - { - // TODO: what even is this? why Attribute constructor wants to call Driver method which must return an instance of Attribute? ?!?!?! - return new ( - foreground, - background - ); - } - /// Event fired when a key is pressed down. This is a precursor to . public event EventHandler? KeyDown; diff --git a/Terminal.Gui/Drivers/ConsoleKeyMapping.cs b/Terminal.Gui/Drivers/ConsoleKeyMapping.cs index 8e9964147..ca8fd6d6f 100644 --- a/Terminal.Gui/Drivers/ConsoleKeyMapping.cs +++ b/Terminal.Gui/Drivers/ConsoleKeyMapping.cs @@ -533,7 +533,7 @@ public static class ConsoleKeyMapping /// /// Get the output character from the , with the correct - /// and the scan code used on . + /// and the scan code used on Windows. /// /// The unicode character. /// The modifiers keys. diff --git a/Terminal.Gui/Drivers/ConsoleSizeMonitor.cs b/Terminal.Gui/Drivers/ConsoleSizeMonitor.cs new file mode 100644 index 000000000..e5999dd39 --- /dev/null +++ b/Terminal.Gui/Drivers/ConsoleSizeMonitor.cs @@ -0,0 +1,35 @@ +#nullable enable +using Microsoft.Extensions.Logging; + +namespace Terminal.Gui.Drivers; + +/// +internal class ConsoleSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer _) : IConsoleSizeMonitor +{ + private Size _lastSize = Size.Empty; + + /// Invoked when the terminal's size changed. The new size of the terminal is provided. + public event EventHandler? SizeChanged; + + /// + public bool Poll () + { + if (ConsoleDriver.RunningUnitTests) + { + return false; + } + + Size size = consoleOut.GetSize (); + + if (size != _lastSize) + { + Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}"); + _lastSize = size; + SizeChanged?.Invoke (this, new (size)); + + return true; + } + + return false; + } +} diff --git a/Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs b/Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs index d1c70526d..a97ec407b 100644 --- a/Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs +++ b/Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs @@ -35,7 +35,7 @@ public class NetOutput : OutputBase, IConsoleOutput /// - public Size GetWindowSize () + public Size GetSize () { if (ConsoleDriver.RunningUnitTests) { @@ -49,6 +49,12 @@ public class NetOutput : OutputBase, IConsoleOutput /// public void SetCursorPosition (int col, int row) { SetCursorPositionImpl (col, row); } + /// + public void SetSize (int width, int height) + { + // Do Nothing. + } + private Point? _lastCursorPosition; /// diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeClipboard.cs b/Terminal.Gui/Drivers/FakeDriver/FakeClipboard.cs new file mode 100644 index 000000000..6951b7923 --- /dev/null +++ b/Terminal.Gui/Drivers/FakeDriver/FakeClipboard.cs @@ -0,0 +1,59 @@ +#nullable enable +namespace Terminal.Gui.Drivers; + +/// +/// Implements a fake clipboard for testing purposes. +/// +public class FakeClipboard : ClipboardBase +{ + /// + /// Gets or sets an exception to be thrown by clipboard operations. + /// + public Exception? FakeException { get; set; } + + private readonly bool _isSupportedAlwaysFalse; + private string _contents = string.Empty; + + /// + /// Constructs a new instance of . + /// + /// + /// + public FakeClipboard ( + bool fakeClipboardThrowsNotSupportedException = false, + bool isSupportedAlwaysFalse = false + ) + { + _isSupportedAlwaysFalse = isSupportedAlwaysFalse; + + if (fakeClipboardThrowsNotSupportedException) + { + FakeException = new NotSupportedException ("Fake clipboard exception"); + } + } + + /// + public override bool IsSupported => !_isSupportedAlwaysFalse; + + /// + protected override string GetClipboardDataImpl () + { + if (FakeException is { }) + { + throw FakeException; + } + + return _contents; + } + + /// + protected override void SetClipboardDataImpl (string? text) + { + if (FakeException is { }) + { + throw FakeException; + } + + _contents = text ?? throw new ArgumentNullException (nameof (text)); + } +} diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs b/Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs index b3d6f4fec..2314649bc 100644 --- a/Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs +++ b/Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs @@ -42,8 +42,9 @@ public class FakeComponentFactory : ComponentFactory } /// - public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) + public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { - return new FakeWindowSizeMonitor(consoleOutput, outputBuffer); + outputBuffer.SetSize(consoleOutput.GetSize().Width, consoleOutput.GetSize().Height); + return new ConsoleSizeMonitor (consoleOutput, outputBuffer); } } diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs b/Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs index 9eb566768..1b43a6b39 100644 --- a/Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs +++ b/Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs @@ -32,10 +32,10 @@ public static class FakeConsole #pragma warning disable RCS1138 // Add summary to documentation comment. /// Specifies the initial console width. - public const int WIDTH = 80; + public const int WIDTH = 0; /// Specifies the initial console height. - public const int HEIGHT = 25; + public const int HEIGHT = 0; /// public static int WindowWidth { get; set; } = WIDTH; @@ -971,7 +971,7 @@ public static class FakeConsole /// /// /// - public static void SetWindowSize (int width, int height) + public static void SetConsoleSize (int width, int height) { WindowWidth = width; WindowHeight = height; diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs b/Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs index e36c6edac..07c59e224 100644 --- a/Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs +++ b/Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs @@ -1,33 +1,28 @@ #nullable enable -using System; -using System.Text; - namespace Terminal.Gui.Drivers; /// -/// Fake console output for testing that captures what would be written to the console. +/// Fake console output for testing that captures what would be written to the console. /// public class FakeConsoleOutput : OutputBase, IConsoleOutput { private readonly StringBuilder _output = new (); private int _cursorLeft; private int _cursorTop; - private Size _windowSize = new (80, 25); + private Size _consoleSize = new (80, 25); /// - /// Gets the captured output as a string. + /// Gets the captured output as a string. /// public string Output => _output.ToString (); - /// - /// Clears the captured output. - /// - public void ClearOutput () => _output.Clear (); - /// - public void SetCursorPosition (int col, int row) + public void SetCursorPosition (int col, int row) { SetCursorPositionImpl (col, row); } + + /// + public void SetSize (int width, int height) { - SetCursorPositionImpl (col, row); + _consoleSize = new (width, height); } /// @@ -35,30 +30,25 @@ public class FakeConsoleOutput : OutputBase, IConsoleOutput { _cursorLeft = col; _cursorTop = row; + return true; } /// - /// Sets the fake window size. + /// Sets the fake window size. /// - public void SetWindowSize (int width, int height) - { - _windowSize = new Size (width, height); - } + public void SetConsoleSize (int width, int height) { _consoleSize = new (width, height); } /// - /// Gets the current cursor position. + /// Gets the current cursor position. /// - public (int left, int top) GetCursorPosition () => (_cursorLeft, _cursorTop); + public (int left, int top) GetCursorPosition () { return (_cursorLeft, _cursorTop); } /// - public Size GetWindowSize () => _windowSize; + public Size GetSize () { return _consoleSize; } /// - public void Write (ReadOnlySpan text) - { - _output.Append (text); - } + public void Write (ReadOnlySpan text) { _output.Append (text); } /// public override void SetCursorVisibility (CursorVisibility visibility) @@ -80,9 +70,5 @@ public class FakeConsoleOutput : OutputBase, IConsoleOutput } /// - protected override void Write (StringBuilder output) - { - _output.Append (output); - } - + protected override void Write (StringBuilder output) { _output.Append (output); } } diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs index 916760c97..2c1f2d474 100644 --- a/Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs @@ -1,4 +1,5 @@ #nullable enable + // // FakeDriver.cs: A fake IConsoleDriver for unit tests. // @@ -6,8 +7,6 @@ using System.Diagnostics; using System.Runtime.InteropServices; -// Alias Console to MockConsole so we don't accidentally use Console - namespace Terminal.Gui.Drivers; /// Implements a mock IConsoleDriver for unit testing @@ -28,8 +27,8 @@ public class FakeDriver : ConsoleDriver FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; // double check usage is correct - Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); - Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); + Debug.Assert (!useFakeClipboard && !fakeClipboardAlwaysThrowsNotSupportedException); + Debug.Assert (!useFakeClipboard && !fakeClipboardIsSupportedAlwaysTrue); } public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; } @@ -40,19 +39,16 @@ public class FakeDriver : ConsoleDriver public static Behaviors FakeBehaviors { get; } = new (); public override bool SupportsTrueColor => false; - /// - public override void WriteRaw (string ansi) - { - - } + /// + public override void WriteRaw (string ansi) { } public FakeDriver () { // FakeDriver implies UnitTests RunningUnitTests = true; - base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH; - base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; + //base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH; + //base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; if (FakeBehaviors.UseFakeClipboard) { @@ -95,16 +91,19 @@ public class FakeDriver : ConsoleDriver { FakeConsole.MockKeyPresses.Clear (); - Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH; - Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; + //Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH; + //Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; FakeConsole.Clear (); + + SetScreenSize (80,25); ResizeScreen (); - CurrentAttribute = new Attribute (Color.White, Color.Black); + ClearContents (); + CurrentAttribute = new (Color.White, Color.Black); } public override bool UpdateScreen () { - bool updated = false; + var updated = false; int savedRow = FakeConsole.CursorTop; int savedCol = FakeConsole.CursorLeft; @@ -223,119 +222,10 @@ public class FakeDriver : ConsoleDriver FakeConsole.CursorTop = savedRow; FakeConsole.CursorLeft = savedCol; FakeConsole.CursorVisible = savedCursorVisible; + return updated; } - - #region Color Handling - - ///// - ///// In the FakeDriver, colors are encoded as an int; same as DotNetDriver - ///// However, the foreground color is stored in the most significant 16 bits, - ///// and the background color is stored in the least significant 16 bits. - ///// - //public override Attribute MakeColor (Color foreground, Color background) - //{ - // // Encode the colors into the int value. - // return new Attribute ( - // foreground: foreground, - // background: background - // ); - //} - - #endregion - - private KeyCode MapKey (ConsoleKeyInfo keyInfo) - { - switch (keyInfo.Key) - { - case ConsoleKey.Escape: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Esc); - case ConsoleKey.Tab: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Tab); - case ConsoleKey.Clear: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Clear); - case ConsoleKey.Home: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Home); - case ConsoleKey.End: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.End); - case ConsoleKey.LeftArrow: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorLeft); - case ConsoleKey.RightArrow: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorRight); - case ConsoleKey.UpArrow: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorUp); - case ConsoleKey.DownArrow: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorDown); - case ConsoleKey.PageUp: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageUp); - case ConsoleKey.PageDown: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageDown); - case ConsoleKey.Enter: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Enter); - case ConsoleKey.Spacebar: - return ConsoleKeyMapping.MapToKeyCodeModifiers ( - keyInfo.Modifiers, - keyInfo.KeyChar == 0 - ? KeyCode.Space - : (KeyCode)keyInfo.KeyChar - ); - case ConsoleKey.Backspace: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Backspace); - case ConsoleKey.Delete: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Delete); - case ConsoleKey.Insert: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Insert); - case ConsoleKey.PrintScreen: - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PrintScreen); - - case ConsoleKey.Oem1: - case ConsoleKey.Oem2: - case ConsoleKey.Oem3: - case ConsoleKey.Oem4: - case ConsoleKey.Oem5: - case ConsoleKey.Oem6: - case ConsoleKey.Oem7: - case ConsoleKey.Oem8: - case ConsoleKey.Oem102: - case ConsoleKey.OemPeriod: - case ConsoleKey.OemComma: - case ConsoleKey.OemPlus: - case ConsoleKey.OemMinus: - if (keyInfo.KeyChar == 0) - { - return KeyCode.Null; - } - - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar); - } - - ConsoleKey key = keyInfo.Key; - - if (key >= ConsoleKey.A && key <= ConsoleKey.Z) - { - int delta = key - ConsoleKey.A; - - if (keyInfo.KeyChar != (uint)key) - { - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.Key); - } - - if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control) - || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt) - || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Shift)) - { - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)KeyCode.A + delta)); - } - - char alphaBase = keyInfo.Modifiers != ConsoleModifiers.Shift ? 'A' : 'a'; - - return (KeyCode)((uint)alphaBase + delta); - } - - return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar); - } - private CursorVisibility _savedCursorVisibility; /// @@ -356,7 +246,6 @@ public class FakeDriver : ConsoleDriver return FakeConsole.CursorVisible = visibility == CursorVisibility.Default; } - /// private bool EnsureCursorVisibility () { if (!(Col >= 0 && Row >= 0 && Col < Cols && Row < Rows)) @@ -373,23 +262,32 @@ public class FakeDriver : ConsoleDriver return FakeConsole.CursorVisible; } - private AnsiResponseParser _parser = new (); + private readonly AnsiResponseParser _parser = new (); - /// - internal override IAnsiResponseParser GetParser () => _parser; + /// + internal override IAnsiResponseParser GetParser () { return _parser; } + + /// + /// Sets the screen size for testing purposes. Only available in FakeDriver. + /// This method updates the driver's dimensions and triggers the ScreenChanged event. + /// + /// The new width in columns. + /// The new height in rows. + public override void SetScreenSize (int width, int height) { SetBufferSize (width, height); } public void SetBufferSize (int width, int height) { FakeConsole.SetBufferSize (width, height); Cols = width; Rows = height; - SetWindowSize (width, height); + SetConsoleSize (width, height); ProcessResize (); } - public void SetWindowSize (int width, int height) + public void SetConsoleSize (int width, int height) { - FakeConsole.SetWindowSize (width, height); + FakeConsole.SetConsoleSize (width, height); + FakeConsole.SetBufferSize (width, height); if (width != Cols || height != Rows) { @@ -416,7 +314,7 @@ public class FakeDriver : ConsoleDriver { ResizeScreen (); ClearContents (); - OnSizeChanged (new SizeChangedEventArgs (new (Cols, Rows))); + OnSizeChanged (new (new (Cols, Rows))); } public virtual void ResizeScreen () @@ -452,7 +350,7 @@ public class FakeDriver : ConsoleDriver return; } - // Prevents the exception of size changing during resizing. + // Prevents the exception to size changing during resizing. try { // BUGBUG: Why is this using BufferWidth/Height and now Cols/Rows? @@ -476,48 +374,6 @@ public class FakeDriver : ConsoleDriver #endregion - public class FakeClipboard : ClipboardBase - { - public Exception? FakeException { get; set; } - - private readonly bool _isSupportedAlwaysFalse; - private string _contents = string.Empty; - - public FakeClipboard ( - bool fakeClipboardThrowsNotSupportedException = false, - bool isSupportedAlwaysFalse = false - ) - { - _isSupportedAlwaysFalse = isSupportedAlwaysFalse; - - if (fakeClipboardThrowsNotSupportedException) - { - FakeException = new NotSupportedException ("Fake clipboard exception"); - } - } - - public override bool IsSupported => !_isSupportedAlwaysFalse; - - protected override string GetClipboardDataImpl () - { - if (FakeException is { }) - { - throw FakeException; - } - - return _contents; - } - - protected override void SetClipboardDataImpl (string? text) - { - if (FakeException is { }) - { - throw FakeException; - } - - _contents = text ?? throw new ArgumentNullException (nameof (text)); - } - } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -} +} \ No newline at end of file diff --git a/Terminal.Gui/Drivers/FakeDriver/FakeWindowSizeMonitor.cs b/Terminal.Gui/Drivers/FakeDriver/FakeWindowSizeMonitor.cs deleted file mode 100644 index 329be232d..000000000 --- a/Terminal.Gui/Drivers/FakeDriver/FakeWindowSizeMonitor.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Terminal.Gui.Drivers; - -internal class FakeWindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer) : IWindowSizeMonitor -{ - private Size _lastSize = new (0, 0); - - /// Invoked when the terminal's size changed. The new size of the terminal is provided. - public event EventHandler SizeChanging; - - /// Raises the event with the specified size. Used for testing. - /// The new size to report. - public void RaiseSizeChanging (Size newSize) - { - SizeChanging?.Invoke (this, new (newSize)); - } - - /// - public bool Poll () - { - if (ConsoleDriver.RunningUnitTests) - { - return false; - } - - Size size = consoleOut.GetWindowSize (); - - if (size != _lastSize) - { - Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}"); - outputBuffer.SetWindowSize (size.Width, size.Height); - _lastSize = size; - SizeChanging?.Invoke (this, new (size)); - - return true; - } - - return false; - } -} diff --git a/Terminal.Gui/Drivers/IComponentFactory.cs b/Terminal.Gui/Drivers/IComponentFactory.cs index 64bf7aaa9..f7120c274 100644 --- a/Terminal.Gui/Drivers/IComponentFactory.cs +++ b/Terminal.Gui/Drivers/IComponentFactory.cs @@ -41,11 +41,11 @@ public interface IComponentFactory : IComponentFactory IInputProcessor CreateInputProcessor (ConcurrentQueue inputBuffer); /// - /// Creates class for the current driver implementation i.e. the class responsible for - /// reporting the current size of the terminal window. + /// Creates class for the current driver implementation i.e. the class responsible for + /// reporting the current size of the terminal. /// /// /// /// - IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer); + IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer); } diff --git a/Terminal.Gui/Drivers/IConsoleDriver.cs b/Terminal.Gui/Drivers/IConsoleDriver.cs index a28671a4e..b65fca43f 100644 --- a/Terminal.Gui/Drivers/IConsoleDriver.cs +++ b/Terminal.Gui/Drivers/IConsoleDriver.cs @@ -14,6 +14,15 @@ public interface IConsoleDriver /// Gets the location and size of the terminal screen. Rectangle Screen { get; } + /// + /// Sets the screen size for testing purposes. Only supported by FakeDriver. + /// is the source of truth for screen dimensions. + /// + /// The new width in columns. + /// The new height in rows. + /// Thrown when called on non-FakeDriver instances. + void SetScreenSize (int width, int height); + /// /// Gets or sets the clip rectangle that and are subject /// to. @@ -200,11 +209,14 @@ public interface IConsoleDriver /// upon success bool SetCursorVisibility (CursorVisibility visibility); - /// The event fired when the terminal is resized. + /// + /// The event fired when the screen changes (size, position, etc.). + /// is the source of truth for screen dimensions. + /// event EventHandler? SizeChanged; /// Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver. - /// This is only implemented in . + /// This is only implemented in UnixDriver. void Suspend (); /// @@ -228,12 +240,6 @@ public interface IConsoleDriver /// The current attribute. Attribute GetAttribute (); - /// Makes an . - /// The foreground color. - /// The background color. - /// The attribute for the foreground and background colors. - Attribute MakeColor (in Color foreground, in Color background); - /// Event fired when a mouse event occurs. event EventHandler? MouseEvent; diff --git a/Terminal.Gui/Drivers/IConsoleDriverFacade.cs b/Terminal.Gui/Drivers/IConsoleDriverFacade.cs index 2d854e16b..bf150af74 100644 --- a/Terminal.Gui/Drivers/IConsoleDriverFacade.cs +++ b/Terminal.Gui/Drivers/IConsoleDriverFacade.cs @@ -22,5 +22,5 @@ public interface IConsoleDriverFacade /// Interface for classes responsible for reporting the current /// size of the terminal window. /// - IWindowSizeMonitor WindowSizeMonitor { get; } + IConsoleSizeMonitor ConsoleSizeMonitor { get; } } diff --git a/Terminal.Gui/Drivers/IConsoleOutput.cs b/Terminal.Gui/Drivers/IConsoleOutput.cs index aa35c06ee..4bb768c86 100644 --- a/Terminal.Gui/Drivers/IConsoleOutput.cs +++ b/Terminal.Gui/Drivers/IConsoleOutput.cs @@ -20,11 +20,11 @@ public interface IConsoleOutput : IDisposable void Write (IOutputBuffer buffer); /// - /// Returns the current size of the console window in rows/columns (i.e. + /// Returns the current size of the console in rows/columns (i.e. /// of characters not pixels). /// /// - public Size GetWindowSize (); + public Size GetSize (); /// /// Updates the console cursor (the blinking underscore) to be hidden, @@ -39,4 +39,11 @@ public interface IConsoleOutput : IDisposable /// /// void SetCursorPosition (int col, int row); + + /// + /// Sets the size of the console.. + /// + /// + /// + void SetSize (int width, int height); } diff --git a/Terminal.Gui/Drivers/IWindowSizeMonitor.cs b/Terminal.Gui/Drivers/IConsoleSizeMonitor.cs similarity index 77% rename from Terminal.Gui/Drivers/IWindowSizeMonitor.cs rename to Terminal.Gui/Drivers/IConsoleSizeMonitor.cs index 2cee6e8a8..b34503f17 100644 --- a/Terminal.Gui/Drivers/IWindowSizeMonitor.cs +++ b/Terminal.Gui/Drivers/IConsoleSizeMonitor.cs @@ -6,13 +6,13 @@ namespace Terminal.Gui.Drivers; /// Interface for classes responsible for reporting the current /// size of the terminal window. /// -public interface IWindowSizeMonitor +public interface IConsoleSizeMonitor { /// Invoked when the terminal's size changed. The new size of the terminal is provided. - event EventHandler? SizeChanging; + event EventHandler? SizeChanged; /// - /// Examines the current size of the terminal and raises if it is different + /// Examines the current size of the terminal and raises if it is different /// from last inspection. /// /// diff --git a/Terminal.Gui/Drivers/IInputProcessor.cs b/Terminal.Gui/Drivers/IInputProcessor.cs index 8366788af..007825f61 100644 --- a/Terminal.Gui/Drivers/IInputProcessor.cs +++ b/Terminal.Gui/Drivers/IInputProcessor.cs @@ -28,7 +28,7 @@ public interface IInputProcessor /// /// Gets the name of the driver associated with this input processor. /// - string DriverName { get; init; } + string? DriverName { get; init; } /// /// Called when a key is pressed down. Fires the event. This is a precursor to diff --git a/Terminal.Gui/Drivers/IOutputBuffer.cs b/Terminal.Gui/Drivers/IOutputBuffer.cs index 4ca6be377..66498f4f6 100644 --- a/Terminal.Gui/Drivers/IOutputBuffer.cs +++ b/Terminal.Gui/Drivers/IOutputBuffer.cs @@ -97,7 +97,7 @@ public interface IOutputBuffer /// /// /// - void SetWindowSize (int cols, int rows); + void SetSize (int cols, int rows); /// /// Fills the given with the given diff --git a/Terminal.Gui/Drivers/InputProcessor.cs b/Terminal.Gui/Drivers/InputProcessor.cs index 667d4d267..15d320ba2 100644 --- a/Terminal.Gui/Drivers/InputProcessor.cs +++ b/Terminal.Gui/Drivers/InputProcessor.cs @@ -31,7 +31,7 @@ public abstract class InputProcessor : IInputProcessor public ConcurrentQueue InputBuffer { get; } /// - public string DriverName { get; init; } + public string? DriverName { get; init; } /// public IAnsiResponseParser GetParser () { return Parser; } @@ -166,7 +166,7 @@ public abstract class InputProcessor : IInputProcessor /// protected abstract void ProcessAfterParsing (T input); - internal char _highSurrogate = '\0'; + private char _highSurrogate = '\0'; /// public bool IsValidInput (Key key, out Key result) diff --git a/Terminal.Gui/Drivers/MouseButtonStateEx.cs b/Terminal.Gui/Drivers/MouseButtonStateEx.cs index 099151c2c..e6e2a1e96 100644 --- a/Terminal.Gui/Drivers/MouseButtonStateEx.cs +++ b/Terminal.Gui/Drivers/MouseButtonStateEx.cs @@ -3,7 +3,7 @@ namespace Terminal.Gui.Drivers; /// -/// Not to be confused with +/// Not to be confused with NetEvents.MouseButtonState /// internal class MouseButtonStateEx { diff --git a/Terminal.Gui/Drivers/OutputBase.cs b/Terminal.Gui/Drivers/OutputBase.cs index 8393061b4..4222ec6e1 100644 --- a/Terminal.Gui/Drivers/OutputBase.cs +++ b/Terminal.Gui/Drivers/OutputBase.cs @@ -56,7 +56,7 @@ public abstract class OutputBase for (; col < cols; col++) { - if (!buffer.Contents [row, col].IsDirty) + if (!buffer.Contents! [row, col].IsDirty) { if (output.Length > 0) { diff --git a/Terminal.Gui/Drivers/OutputBuffer.cs b/Terminal.Gui/Drivers/OutputBuffer.cs index 039d3f22f..0d3efcfac 100644 --- a/Terminal.Gui/Drivers/OutputBuffer.cs +++ b/Terminal.Gui/Drivers/OutputBuffer.cs @@ -5,7 +5,7 @@ namespace Terminal.Gui.Drivers; /// /// Stores the desired output state for the whole application. This is updated during -/// draw operations before being flushed to the console as part of +/// draw operations before being flushed to the console as part of the main loop. /// operation /// public class OutputBuffer : IOutputBuffer @@ -15,7 +15,7 @@ public class OutputBuffer : IOutputBuffer /// UpdateScreen is called. /// The format of the array is rows, columns. The first index is the row, the second index is the column. /// - public Cell [,] Contents { get; set; } = new Cell[0, 0]; + public Cell [,]? Contents { get; set; } = new Cell[0, 0]; private int _cols; private int _rows; @@ -365,7 +365,7 @@ public class OutputBuffer : IOutputBuffer } /// - public void SetWindowSize (int cols, int rows) + public void SetSize (int cols, int rows) { Cols = cols; Rows = rows; diff --git a/Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs b/Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs index 9643223d3..9313e2bfd 100644 --- a/Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs +++ b/Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs @@ -121,7 +121,7 @@ internal class UnixOutput : OutputBase, IConsoleOutput } /// - public Size GetWindowSize () + public Size GetSize () { if (ConsoleDriver.RunningUnitTests) { @@ -168,6 +168,12 @@ internal class UnixOutput : OutputBase, IConsoleOutput SetCursorPositionImpl (col, row); } + /// + public void SetSize (int width, int height) + { + // Do nothing + } + /// public void Dispose () { diff --git a/Terminal.Gui/Drivers/WindowSizeMonitor.cs b/Terminal.Gui/Drivers/WindowSizeMonitor.cs deleted file mode 100644 index ee3841c6e..000000000 --- a/Terminal.Gui/Drivers/WindowSizeMonitor.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Terminal.Gui.Drivers; - -internal class WindowSizeMonitor : IWindowSizeMonitor -{ - private readonly IConsoleOutput _consoleOut; - private readonly IOutputBuffer _outputBuffer; - private Size _lastSize = new (0, 0); - - /// Invoked when the terminal's size changed. The new size of the terminal is provided. - public event EventHandler SizeChanging; - - public WindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer) - { - _consoleOut = consoleOut; - _outputBuffer = outputBuffer; - } - - /// - public bool Poll () - { - if (ConsoleDriver.RunningUnitTests) - { - return false; - } - - Size size = _consoleOut.GetWindowSize (); - - if (size != _lastSize) - { - Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}"); - _outputBuffer.SetWindowSize (size.Width, size.Height); - _lastSize = size; - SizeChanging?.Invoke (this, new (size)); - - return true; - } - - return false; - } -} diff --git a/Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs b/Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs index 46f9eb742..abff1ca0c 100644 --- a/Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs +++ b/Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs @@ -1,719 +1,25 @@ #nullable enable -using System.Collections.Concurrent; -using System.ComponentModel; using System.Runtime.InteropServices; -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member -#pragma warning disable IDE1006// Naming rule violation: Prefix '_' is not expected + +// ReSharper disable InconsistentNaming namespace Terminal.Gui.Drivers; -public partial class WindowsConsole -{ - private CancellationTokenSource? _inputReadyCancellationTokenSource; - private readonly BlockingCollection _inputQueue = new (new ConcurrentQueue ()); +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - public const int STD_OUTPUT_HANDLE = -11; +/// +/// Definitions for Windows Console API structures and constants. +/// +public class WindowsConsole +{ + /// + /// Standard input handle constant. + /// public const int STD_INPUT_HANDLE = -10; - private readonly nint _inputHandle; - private nint _outputHandle; - private nint _screenBuffer; - private readonly uint _originalConsoleMode; - private CursorVisibility? _initialCursorVisibility; - private CursorVisibility? _currentCursorVisibility; - private CursorVisibility? _pendingCursorVisibility; - private readonly StringBuilder _stringBuilder = new (256 * 1024); - private string _lastWrite = string.Empty; - - public WindowsConsole () - { - _inputHandle = GetStdHandle (STD_INPUT_HANDLE); - _outputHandle = GetStdHandle (STD_OUTPUT_HANDLE); - _originalConsoleMode = ConsoleMode; - uint newConsoleMode = _originalConsoleMode; - newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags); - newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode; - newConsoleMode &= ~(uint)ConsoleModes.EnableProcessedInput; - ConsoleMode = newConsoleMode; - - IsVirtualTerminal = GetConsoleMode (_outputHandle, out uint mode) && (mode & (uint)ConsoleModes.EnableVirtualTerminalProcessing) != 0; - - if (!IsVirtualTerminal) - { - CreateConsoleScreenBuffer (); - Size bufferSize = GetConsoleBufferWindow (out _); - SmallRect window = new () - { - Top = 0, - Left = 0, - Bottom = (short)bufferSize.Height, - Right = (short)bufferSize.Width - }; - - ReadFromConsoleOutput (bufferSize, new ((short)bufferSize.Width, (short)bufferSize.Height), ref window); - - if (!GetConsoleMode (_screenBuffer, out mode)) - { - throw new ApplicationException ($"Failed to get screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}."); - } - - const uint ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002; - - mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; // Disable wrap - - if (!SetConsoleMode (_screenBuffer, mode)) - { - throw new ApplicationException ($"Failed to set screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}."); - } - } - - SetInitialCursorVisibility (); - - _inputReadyCancellationTokenSource = new (); - Task.Run (ProcessInputQueue, _inputReadyCancellationTokenSource.Token); - } - - private void CreateConsoleScreenBuffer () - { - _screenBuffer = CreateConsoleScreenBuffer ( - DesiredAccess.GenericRead | DesiredAccess.GenericWrite, - ShareMode.FileShareRead | ShareMode.FileShareWrite, - nint.Zero, - 1, - nint.Zero - ); - - if (_screenBuffer == INVALID_HANDLE_VALUE) - { - int err = Marshal.GetLastWin32Error (); - - if (err != 0) - { - throw new Win32Exception (err); - } - } - - if (!SetConsoleActiveScreenBuffer (_screenBuffer)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - } - - public InputRecord? DequeueInput () - { - while (_inputReadyCancellationTokenSource is { }) - { - try - { - return _inputQueue.Take (_inputReadyCancellationTokenSource.Token); - } - catch (OperationCanceledException) - { - return null; - } - } - - return null; - } - - public InputRecord? ReadConsoleInput () - { - const int BUFFER_SIZE = 1; - InputRecord inputRecord = default; - uint numberEventsRead = 0; - - while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) - { - try - { - // Peek to check if there is any input available - if (PeekConsoleInput (_inputHandle, out _, BUFFER_SIZE, out uint eventsRead) && eventsRead > 0) - { - // Read the input since it is available - ReadConsoleInput ( - _inputHandle, - out inputRecord, - BUFFER_SIZE, - out numberEventsRead); - } - - if (numberEventsRead > 0) - { - return inputRecord; - } - - try - { - Task.Delay (100, _inputReadyCancellationTokenSource.Token).Wait (_inputReadyCancellationTokenSource.Token); - } - catch (OperationCanceledException) - { - return null; - } - } - catch (Exception ex) - { - if (ex is OperationCanceledException or ObjectDisposedException) - { - return null; - } - - throw; - } - } - - return null; - } - - private void ProcessInputQueue () - { - while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) - { - try - { - if (_inputQueue.Count == 0) - { - while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) - { - try - { - InputRecord? inpRec = ReadConsoleInput (); - - if (inpRec is { }) - { - _inputQueue.Add (inpRec.Value); - - break; - } - } - catch (OperationCanceledException) - { - return; - } - } - } - } - catch (OperationCanceledException) - { - return; - } - } - } - - - // Last text style used, for updating style with EscSeqUtils.CSI_AppendTextStyleChange(). - private TextStyle _redrawTextStyle = TextStyle.None; - - private CharInfo []? _originalStdOutChars; - - private struct Run - { - public ushort attr; - public string text; - - public Run (ushort attr, string text) - { - this.attr = attr; - this.text = text; - } - } - - public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord bufferSize, SmallRect window, bool force16Colors) - { - //Debug.WriteLine ("WriteToConsole"); - - Attribute? prev = null; - var result = false; - - if (force16Colors) - { - _stringBuilder.Clear (); - - var i = 0; - List runs = []; - Run? current = null; - SetCursorPosition (new Coord (0, 0)); - - foreach (ExtendedCharInfo info in charInfoBuffer) - { - if (IsVirtualTerminal) - { - Attribute attr = info.Attribute; - AnsiColorCode fgColor = info.Attribute.Foreground.GetAnsiColorCode (); - AnsiColorCode bgColor = info.Attribute.Background.GetAnsiColorCode (); - - if (attr != prev) - { - prev = attr; - _stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColor (fgColor)); - _stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColor (bgColor)); - - EscSeqUtils.CSI_AppendTextStyleChange (_stringBuilder, _redrawTextStyle, attr.Style); - _redrawTextStyle = attr.Style; - } - - if (info.Char [0] != '\x1b') - { - if (!info.Empty) - { - _stringBuilder.Append (info.Char); - } - } - else - { - _stringBuilder.Append (' '); - } - } - else - { - if (info.Empty) - { - i++; - continue; - } - - if (!info.Empty) - { - var attr = (ushort)((int)info.Attribute.Foreground.GetClosestNamedColor16 () - | ((int)info.Attribute.Background.GetClosestNamedColor16 () << 4)); - - // Start new run if needed - if (current == null || attr != current.Value.attr) - { - if (current != null) - { - runs.Add (new (current.Value.attr, _stringBuilder.ToString ())); - } - - _stringBuilder.Clear (); - current = new Run (attr, ""); - } - - _stringBuilder!.Append (info.Char); - } - - i++; - - if (i > 0 && i <= charInfoBuffer.Length && i % bufferSize.X == 0) - { - if (i < charInfoBuffer.Length) - { - _stringBuilder.AppendLine (); - } - - runs.Add (new (current!.Value.attr, _stringBuilder.ToString ())); - _stringBuilder.Clear (); - } - } - } - - if (IsVirtualTerminal) - { - _stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition); - _stringBuilder.Append (EscSeqUtils.CSI_HideCursor); - - var s = _stringBuilder.ToString (); - - // TODO: requires extensive testing if we go down this route - // If console output has changed - if (s != _lastWrite) - { - // supply console with the new content - result = WriteConsole (_outputHandle, s, (uint)s.Length, out uint _, nint.Zero); - } - - _lastWrite = s; - - foreach (var sixel in Application.Sixel) - { - SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y)); - WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero); - } - } - else - { - foreach (var run in runs) - { - SetConsoleTextAttribute (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.attr); - result = WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.text, (uint)run.text.Length, out _, nint.Zero); - } - } - } - else - { - _stringBuilder.Clear (); - - _stringBuilder.Append (EscSeqUtils.CSI_SaveCursorPosition); - EscSeqUtils.CSI_AppendCursorPosition (_stringBuilder, 0, 0); - - foreach (ExtendedCharInfo info in charInfoBuffer) - { - Attribute attr = info.Attribute; - - if (attr != prev) - { - prev = attr; - EscSeqUtils.CSI_AppendForegroundColorRGB (_stringBuilder, attr.Foreground.R, attr.Foreground.G, attr.Foreground.B); - EscSeqUtils.CSI_AppendBackgroundColorRGB (_stringBuilder, attr.Background.R, attr.Background.G, attr.Background.B); - EscSeqUtils.CSI_AppendTextStyleChange (_stringBuilder, _redrawTextStyle, attr.Style); - _redrawTextStyle = attr.Style; - } - - if (info.Char [0] != '\x1b') - { - if (!info.Empty) - { - _stringBuilder.Append (info.Char); - } - } - else - { - _stringBuilder.Append (' '); - } - } - - _stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition); - _stringBuilder.Append (EscSeqUtils.CSI_HideCursor); - - var s = _stringBuilder.ToString (); - - // TODO: requires extensive testing if we go down this route - // If console output has changed - if (s != _lastWrite) - { - // supply console with the new content - result = WriteConsole (_outputHandle, s, (uint)s.Length, out uint _, nint.Zero); - } - - _lastWrite = s; - - foreach (var sixel in Application.Sixel) - { - SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y)); - WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero); - } - } - - if (!result) - { - int err = Marshal.GetLastWin32Error (); - - if (err != 0) - { - throw new Win32Exception (err); - } - } - - return result; - } - - internal bool WriteANSI (string ansi) - { - if (WriteConsole (_outputHandle, ansi, (uint)ansi.Length, out uint _, nint.Zero)) - { - // Flush the output to make sure it's sent immediately - return FlushFileBuffers (_outputHandle); - } - - return false; - } - - public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window) - { - _originalStdOutChars = new CharInfo [size.Height * size.Width]; - - if (!ReadConsoleOutput (_screenBuffer, _originalStdOutChars, coords, new Coord { X = 0, Y = 0 }, ref window)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - } - - public bool SetCursorPosition (Coord position) - { - return SetConsoleCursorPosition (IsVirtualTerminal ? _outputHandle : _screenBuffer, position); - } - - public void SetInitialCursorVisibility () - { - if (_initialCursorVisibility.HasValue == false && GetCursorVisibility (out CursorVisibility visibility)) - { - _initialCursorVisibility = visibility; - } - } - - public bool GetCursorVisibility (out CursorVisibility visibility) - { - if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero) - { - visibility = CursorVisibility.Invisible; - - return false; - } - - if (!GetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, out ConsoleCursorInfo info)) - { - int err = Marshal.GetLastWin32Error (); - - if (err != 0) - { - throw new Win32Exception (err); - } - - visibility = CursorVisibility.Default; - - return false; - } - - if (!info.bVisible) - { - visibility = CursorVisibility.Invisible; - } - else if (info.dwSize > 50) - { - visibility = CursorVisibility.Default; - } - else - { - visibility = CursorVisibility.Default; - } - - return visibility != CursorVisibility.Invisible; - } - - public bool EnsureCursorVisibility () - { - if (_initialCursorVisibility.HasValue && _pendingCursorVisibility.HasValue && SetCursorVisibility (_pendingCursorVisibility.Value)) - { - _pendingCursorVisibility = null; - - return true; - } - - return false; - } - - public void ForceRefreshCursorVisibility () - { - if (_currentCursorVisibility.HasValue) - { - _pendingCursorVisibility = _currentCursorVisibility; - _currentCursorVisibility = null; - } - } - - public bool SetCursorVisibility (CursorVisibility visibility) - { - if (_initialCursorVisibility.HasValue == false) - { - _pendingCursorVisibility = visibility; - - return false; - } - - if (_currentCursorVisibility.HasValue == false || _currentCursorVisibility.Value != visibility) - { - var info = new ConsoleCursorInfo - { - dwSize = (uint)visibility & 0x00FF, - bVisible = ((uint)visibility & 0xFF00) != 0 - }; - - if (!SetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref info)) - { - return false; - } - - _currentCursorVisibility = visibility; - } - - return true; - } - - public void Cleanup () - { - if (_initialCursorVisibility.HasValue) - { - SetCursorVisibility (_initialCursorVisibility.Value); - } - - //SetConsoleOutputWindow (out _); - - ConsoleMode = _originalConsoleMode; - - _outputHandle = CreateConsoleScreenBuffer ( - DesiredAccess.GenericRead | DesiredAccess.GenericWrite, - ShareMode.FileShareRead | ShareMode.FileShareWrite, - nint.Zero, - 1, - nint.Zero - ); - - if (!SetConsoleActiveScreenBuffer (_outputHandle)) - { - int err = Marshal.GetLastWin32Error (); - Console.WriteLine ("Error: {0}", err); - } - - if (_screenBuffer != nint.Zero) - { - CloseHandle (_screenBuffer); - } - - _screenBuffer = nint.Zero; - - _inputReadyCancellationTokenSource?.Cancel (); - _inputReadyCancellationTokenSource?.Dispose (); - _inputReadyCancellationTokenSource = null; - } - - internal Size GetConsoleBufferWindow (out Point position) - { - if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero) - { - position = Point.Empty; - - return Size.Empty; - } - - var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX (); - csbi.cbSize = (uint)Marshal.SizeOf (csbi); - - if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi)) - { - //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); - position = Point.Empty; - - return Size.Empty; - } - - Size sz = new ( - csbi.srWindow.Right - csbi.srWindow.Left + 1, - csbi.srWindow.Bottom - csbi.srWindow.Top + 1); - position = new (csbi.srWindow.Left, csbi.srWindow.Top); - - return sz; - } - - internal Size GetConsoleOutputWindow (out Point position) - { - var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX (); - csbi.cbSize = (uint)Marshal.SizeOf (csbi); - - if (!GetConsoleScreenBufferInfoEx (_outputHandle, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - Size sz = new ( - csbi.srWindow.Right - csbi.srWindow.Left + 1, - csbi.srWindow.Bottom - csbi.srWindow.Top + 1); - position = new (csbi.srWindow.Left, csbi.srWindow.Top); - - return sz; - } - - internal Size SetConsoleWindow (short cols, short rows) - { - var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX (); - csbi.cbSize = (uint)Marshal.SizeOf (csbi); - - if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer); - short newCols = Math.Min (cols, maxWinSize.X); - short newRows = Math.Min (rows, maxWinSize.Y); - csbi.dwSize = new Coord (newCols, Math.Max (newRows, (short)1)); - csbi.srWindow = new SmallRect (0, 0, newCols, newRows); - csbi.dwMaximumWindowSize = new Coord (newCols, newRows); - - if (!SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0)); - - if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect)) - { - //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ()); - return new (cols, rows); - } - - SetConsoleOutputWindow (csbi); - - return new (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1); - } - - internal Size GetLargestConsoleWindowSize () - { - Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer); - - return new (maxWinSize.X, maxWinSize.Y); - } - - private void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi) - { - if ((IsVirtualTerminal - ? _outputHandle - : _screenBuffer) != nint.Zero && !SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - } - - internal Size SetConsoleOutputWindow (out Point position) - { - if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero) - { - position = Point.Empty; - - return Size.Empty; - } - - var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX (); - csbi.cbSize = (uint)Marshal.SizeOf (csbi); - - if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - Size sz = new ( - csbi.srWindow.Right - csbi.srWindow.Left + 1, - Math.Max (csbi.srWindow.Bottom - csbi.srWindow.Top + 1, 0)); - position = new (csbi.srWindow.Left, csbi.srWindow.Top); - SetConsoleOutputWindow (csbi); - var winRect = new SmallRect (0, 0, (short)(sz.Width - 1), (short)Math.Max (sz.Height - 1, 0)); - - if (!SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect)) - { - throw new Win32Exception (Marshal.GetLastWin32Error ()); - } - - return sz; - } - - internal bool IsVirtualTerminal { get; init; } - - private uint ConsoleMode - { - get - { - GetConsoleMode (_inputHandle, out uint v); - - return v; - } - set => SetConsoleMode (_inputHandle, value); - } - + /// + /// Windows Console mode flags. + /// [Flags] public enum ConsoleModes : uint { @@ -724,6 +30,9 @@ public partial class WindowsConsole EnableExtendedFlags = 128 } + /// + /// Key event record structure. + /// [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)] public struct KeyEventRecord { @@ -811,11 +120,9 @@ public partial class WindowsConsole public readonly override string ToString () { return $"[Mouse{MousePosition},{ButtonState},{ControlKeyState},{EventFlags}]"; } } - public struct WindowBufferSizeRecord + public struct WindowBufferSizeRecord (short x, short y) { - public Coord _size; - - public WindowBufferSizeRecord (short x, short y) { _size = new Coord (x, y); } + public Coord _size = new (x, y); public readonly override string ToString () { return $"[WindowBufferSize{_size}"; } } @@ -865,41 +172,17 @@ public partial class WindowsConsole public readonly override string ToString () { return (EventType switch - { - EventType.Focus => FocusEvent.ToString (), - EventType.Key => KeyEvent.ToString (), - EventType.Menu => MenuEvent.ToString (), - EventType.Mouse => MouseEvent.ToString (), - EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (), - _ => "Unknown event type: " + EventType - })!; + { + EventType.Focus => FocusEvent.ToString (), + EventType.Key => KeyEvent.ToString (), + EventType.Menu => MenuEvent.ToString (), + EventType.Mouse => MouseEvent.ToString (), + EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (), + _ => "Unknown event type: " + EventType + })!; } } - [Flags] - private enum ShareMode : uint - { - FileShareRead = 1, - FileShareWrite = 2 - } - - [Flags] - private enum DesiredAccess : uint - { - GenericRead = 2147483648, - GenericWrite = 1073741824 - } - - [StructLayout (LayoutKind.Sequential)] - public struct ConsoleScreenBufferInfo - { - public Coord dwSize; - public Coord dwCursorPosition; - public ushort wAttributes; - public SmallRect srWindow; - public Coord dwMaximumWindowSize; - } - [StructLayout (LayoutKind.Sequential)] public struct Coord { @@ -935,20 +218,6 @@ public partial class WindowsConsole public ushort Attributes; } - public struct ExtendedCharInfo - { - public char [] Char { get; set; } - public Attribute Attribute { get; set; } - public bool Empty { get; set; } // TODO: Temp hack until virtual terminal sequences - - public ExtendedCharInfo (char [] character, Attribute attribute) - { - Char = character; - Attribute = attribute; - Empty = false; - } - } - [StructLayout (LayoutKind.Sequential)] public struct SmallRect { @@ -1045,147 +314,19 @@ public partial class WindowsConsole } } - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern nint GetStdHandle (int nStdHandle); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool CloseHandle (nint handle); - - [DllImport ("kernel32.dll", SetLastError = true)] - public static extern bool PeekConsoleInput (nint hConsoleInput, out InputRecord lpBuffer, uint nLength, out uint lpNumberOfEventsRead); - - [DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)] - public static extern bool ReadConsoleInput ( - nint hConsoleInput, - out InputRecord lpBuffer, - uint nLength, - out uint lpNumberOfEventsRead - ); - - [DllImport ("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern bool ReadConsoleOutput ( - nint hConsoleOutput, - [Out] CharInfo [] lpBuffer, - Coord dwBufferSize, - Coord dwBufferCoord, - ref SmallRect lpReadRegion - ); - - // TODO: This API is obsolete. See https://learn.microsoft.com/en-us/windows/console/writeconsoleoutput - [DllImport ("kernel32.dll", EntryPoint = "WriteConsoleOutputW", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool WriteConsoleOutput ( - nint hConsoleOutput, - CharInfo [] lpBuffer, - Coord dwBufferSize, - Coord dwBufferCoord, - ref SmallRect lpWriteRegion - ); - - [LibraryImport ("kernel32.dll", EntryPoint = "WriteConsoleW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] - [return: MarshalAs (UnmanagedType.Bool)] - private static partial bool WriteConsole ( - nint hConsoleOutput, - ReadOnlySpan lpbufer, - uint NumberOfCharsToWriten, - out uint lpNumberOfCharsWritten, - nint lpReserved - ); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleTextAttribute ( - nint hConsoleOutput, - ushort wAttributes - ); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool FlushFileBuffers (nint hFile); - - [DllImport ("kernel32.dll")] - private static extern bool SetConsoleCursorPosition (nint hConsoleOutput, Coord dwCursorPosition); - [StructLayout (LayoutKind.Sequential)] public struct ConsoleCursorInfo { /// - /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100. - /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal - /// line at the bottom of the cell. + /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100. + /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal + /// line at the bottom of the cell. /// public uint dwSize; + public bool bVisible; } - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleCursorInfo (nint hConsoleOutput, [In] ref ConsoleCursorInfo lpConsoleCursorInfo); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool GetConsoleCursorInfo (nint hConsoleOutput, out ConsoleCursorInfo lpConsoleCursorInfo); - - [DllImport ("kernel32.dll")] - private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode); - - [DllImport ("kernel32.dll")] - private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern nint CreateConsoleScreenBuffer ( - DesiredAccess dwDesiredAccess, - ShareMode dwShareMode, - nint secutiryAttributes, - uint flags, - nint screenBufferData - ); - - internal static nint INVALID_HANDLE_VALUE = new (-1); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleActiveScreenBuffer (nint handle); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool GetNumberOfConsoleInputEvents (nint handle, out uint lpcNumberOfEvents); - - internal uint GetNumberOfConsoleInputEvents () - { - if (!GetNumberOfConsoleInputEvents (_inputHandle, out uint numOfEvents)) - { - Console.WriteLine ($"Error: {Marshal.GetLastWin32Error ()}"); - - return 0; - } - - return numOfEvents; - } - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool FlushConsoleInputBuffer (nint handle); - - internal void FlushConsoleInputBuffer () - { - if (!FlushConsoleInputBuffer (_inputHandle)) - { - Console.WriteLine ($"Error: {Marshal.GetLastWin32Error ()}"); - } - } - -#if false // Not needed on the constructor. Perhaps could be used on resizing. To study. - [DllImport ("kernel32.dll", ExactSpelling = true)] - static extern IntPtr GetConsoleWindow (); - - [DllImport ("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - static extern bool ShowWindow (IntPtr hWnd, int nCmdShow); - - public const int HIDE = 0; - public const int MAXIMIZE = 3; - public const int MINIMIZE = 6; - public const int RESTORE = 9; - - internal void ShowWindow (int state) - { - IntPtr thisConsole = GetConsoleWindow (); - ShowWindow (thisConsole, state); - } -#endif - // See: https://github.com/gui-cs/Terminal.Gui/issues/357 [StructLayout (LayoutKind.Sequential)] @@ -1235,22 +376,4 @@ public partial class WindowsConsole [FieldOffset (0)] public uint Value; } - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool GetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX csbi); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX consoleScreenBufferInfo); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleWindowInfo ( - nint hConsoleOutput, - bool bAbsolute, - [In] ref SmallRect lpConsoleWindow - ); - - [DllImport ("kernel32.dll", SetLastError = true)] - private static extern Coord GetLargestConsoleWindowSize ( - nint hConsoleOutput - ); } diff --git a/Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs b/Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs index 94f2c5ec8..12ef0c15d 100644 --- a/Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs +++ b/Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +#nullable enable +using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; using static Terminal.Gui.Drivers.WindowsConsole; @@ -66,13 +67,13 @@ internal class WindowsInput : ConsoleInput, IWindowsInput return false; } - const int bufferSize = 1; // We only need to check if there's at least one event - nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf () * bufferSize); + const int BUFFER_SIZE = 1; // We only need to check if there's at least one event + nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf () * BUFFER_SIZE); try { // Use PeekConsoleInput to inspect the input buffer without removing events - if (PeekConsoleInput (_inputHandle, pRecord, bufferSize, out uint numberOfEventsRead)) + if (PeekConsoleInput (_inputHandle, pRecord, BUFFER_SIZE, out uint numberOfEventsRead)) { // Return true if there's at least one event in the buffer return numberOfEventsRead > 0; @@ -86,7 +87,7 @@ internal class WindowsInput : ConsoleInput, IWindowsInput catch (Exception ex) { // Optionally log the exception - Console.WriteLine ($"Error in Peek: {ex.Message}"); + Console.WriteLine (@$"Error in Peek: {ex.Message}"); return false; } @@ -99,15 +100,15 @@ internal class WindowsInput : ConsoleInput, IWindowsInput protected override IEnumerable Read () { - const int bufferSize = 1; - nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf () * bufferSize); + const int BUFFER_SIZE = 1; + nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf () * BUFFER_SIZE); try { ReadConsoleInput ( _inputHandle, pRecord, - bufferSize, + BUFFER_SIZE, out uint numberEventsRead); return numberEventsRead == 0 diff --git a/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs b/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs index 6c5f806c7..b04b9faa1 100644 --- a/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs +++ b/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs @@ -356,7 +356,7 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput private Size? _lastWindowSizeBeforeMaximized; private bool _lockResize; - public Size GetWindowSize () + public Size GetSize () { if (_lockResize) { @@ -497,6 +497,12 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput } } + /// + public void SetSize (int width, int height) + { + // Do Nothing. + } + private bool _isDisposed; private bool _force16Colors; private nint _consoleBuffer; diff --git a/Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs b/Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs index 999011e3e..b55fec027 100644 --- a/Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs +++ b/Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs @@ -688,7 +688,7 @@ public partial class Border break; case ViewArrangement.BottomResizable: - Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1); + Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1); break; case ViewArrangement.LeftResizable: @@ -705,12 +705,12 @@ public partial class Border break; case ViewArrangement.RightResizable: - Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1); + Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1); break; case ViewArrangement.BottomResizable | ViewArrangement.RightResizable: - Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1); - Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1); + Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1); + Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1); break; case ViewArrangement.BottomResizable | ViewArrangement.LeftResizable: @@ -723,7 +723,7 @@ public partial class Border Parent.X = parentLoc.X - _startGrabPoint.X; } - Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1); + Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1); break; case ViewArrangement.TopResizable | ViewArrangement.RightResizable: @@ -736,7 +736,7 @@ public partial class Border Parent.Y = parentLoc.Y - _startGrabPoint.Y; } - Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1); + Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1); break; case ViewArrangement.TopResizable | ViewArrangement.LeftResizable: diff --git a/Terminal.Gui/ViewBase/Adornment/Border.cs b/Terminal.Gui/ViewBase/Adornment/Border.cs index b092aae1d..18a99b1c1 100644 --- a/Terminal.Gui/ViewBase/Adornment/Border.cs +++ b/Terminal.Gui/ViewBase/Adornment/Border.cs @@ -152,7 +152,7 @@ public partial class Border : Adornment #if SUBVIEW_BASED_BORDER private void OnLayoutStarted (object sender, LayoutEventArgs e) { - _left.Border.LineStyle = LineStyle; + _left.Border!.LineStyle = LineStyle; _left.X = Thickness.Left - 1; _left.Y = Thickness.Top - 1; diff --git a/Terminal.Gui/ViewBase/Adornment/Margin.cs b/Terminal.Gui/ViewBase/Adornment/Margin.cs index 4695d3ee5..59b39930f 100644 --- a/Terminal.Gui/ViewBase/Adornment/Margin.cs +++ b/Terminal.Gui/ViewBase/Adornment/Margin.cs @@ -79,12 +79,12 @@ public class Margin : Adornment if (view.Margin?.GetCachedClip () != null) { - view.Margin.NeedsDraw = true; + view.Margin!.NeedsDraw = true; Region? saved = GetClip (); - View.SetClip (view.Margin.GetCachedClip ()); - view.Margin.Draw (); + View.SetClip (view.Margin!.GetCachedClip ()); + view.Margin!.Draw (); View.SetClip (saved); - view.Margin.ClearCachedClip (); + view.Margin!.ClearCachedClip (); } view.NeedsDraw = false; @@ -292,14 +292,14 @@ public class Margin : Adornment { case ShadowStyle.Transparent: // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner. - _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0; + _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).Y + 1 : 0; break; case ShadowStyle.Opaque: // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner. - _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0; - _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).X + 1 : 0; + _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).Y + 1 : 0; + _bottomShadow.X = Parent.Border!.Thickness.Left > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).X + 1 : 0; break; diff --git a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs b/Terminal.Gui/ViewBase/Adornment/ShadowView.cs index e2dbb7d46..151aa149c 100644 --- a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs +++ b/Terminal.Gui/ViewBase/Adornment/ShadowView.cs @@ -95,7 +95,7 @@ internal class ShadowView : View { for (int c = Math.Max (0, screen.X + 1); c < screen.X + screen.Width; c++) { - Driver.Move (c, r); + Driver?.Move (c, r); SetAttribute (GetAttributeUnderLocation (new (c, r))); if (c < ScreenContents?.GetLength (1) && r < ScreenContents?.GetLength (0)) @@ -129,7 +129,7 @@ internal class ShadowView : View { for (int r = Math.Max (0, screen.Y); r < screen.Y + viewport.Height; r++) { - Driver.Move (c, r); + Driver?.Move (c, r); SetAttribute (GetAttributeUnderLocation (new (c, r))); if (ScreenContents is { } && screen.X < ScreenContents.GetLength (1) && r < ScreenContents.GetLength (0)) diff --git a/Terminal.Gui/ViewBase/Layout/DimAuto.cs b/Terminal.Gui/ViewBase/Layout/DimAuto.cs index 34ad05b19..b70aca542 100644 --- a/Terminal.Gui/ViewBase/Layout/DimAuto.cs +++ b/Terminal.Gui/ViewBase/Layout/DimAuto.cs @@ -35,7 +35,7 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt int screenX4 = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4; int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screenX4; - Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim."); + //Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim."); if (Style.FastHasFlags (DimAutoStyle.Text)) { diff --git a/Terminal.Gui/ViewBase/View.Layout.cs b/Terminal.Gui/ViewBase/View.Layout.cs index 72bb409b3..b12e2b78c 100644 --- a/Terminal.Gui/ViewBase/View.Layout.cs +++ b/Terminal.Gui/ViewBase/View.Layout.cs @@ -37,7 +37,7 @@ public partial class View // Layout APIs /// /// Changing this property will result in and to be set, /// resulting in the - /// view being laid out and redrawn as appropriate in the next iteration of the . + /// view being laid out and redrawn as appropriate in the next iteration. /// /// public Rectangle Frame @@ -219,7 +219,7 @@ public partial class View // Layout APIs /// /// Changing this property will result in and to be set, /// resulting in the - /// view being laid out and redrawn as appropriate in the next iteration of the . + /// view being laid out and redrawn as appropriate in the next iteration. /// /// /// Changing this property will cause to be updated. @@ -264,7 +264,7 @@ public partial class View // Layout APIs /// /// Changing this property will result in and to be set, /// resulting in the - /// view being laid out and redrawn as appropriate in the next iteration of the . + /// view being laid out and redrawn as appropriate in the next iteration. /// /// /// Changing this property will cause to be updated. @@ -308,7 +308,7 @@ public partial class View // Layout APIs /// /// Changing this property will result in and to be set, /// resulting in the - /// view being laid out and redrawn as appropriate in the next iteration of the . + /// view being laid out and redrawn as appropriate in the next iteration. /// /// /// Changing this property will cause to be updated. @@ -396,7 +396,7 @@ public partial class View // Layout APIs /// /// Changing this property will result in and to be set, /// resulting in the - /// view being laid out and redrawn as appropriate in the next iteration of the . + /// view being laid out and redrawn as appropriate in the next iteration. /// /// /// Changing this property will cause to be updated. @@ -843,7 +843,7 @@ public partial class View // Layout APIs /// /// /// - /// The will cause to be called on the next + /// The next iteration will cause to be called on the next /// so there is normally no reason to call see . /// /// @@ -882,12 +882,12 @@ public partial class View // Layout APIs if (current.Margin is { SubViews.Count: > 0 }) { - current.Margin.SetNeedsLayout (); + current.Margin!.SetNeedsLayout (); } if (current.Border is { SubViews.Count: > 0 }) { - current.Border.SetNeedsLayout (); + current.Border!.SetNeedsLayout (); } if (current.Padding is { SubViews.Count: > 0 }) diff --git a/Terminal.Gui/Views/Menuv1/MenuBar.cs b/Terminal.Gui/Views/Menuv1/MenuBar.cs index 8b66a63dc..8f56ed76b 100644 --- a/Terminal.Gui/Views/Menuv1/MenuBar.cs +++ b/Terminal.Gui/Views/Menuv1/MenuBar.cs @@ -1441,8 +1441,8 @@ public class MenuBar : View, IDesignable if (SuperView is { }) { - locationOffset.X += SuperView.Border.Thickness.Left; - locationOffset.Y += SuperView.Border.Thickness.Top; + locationOffset.X += SuperView.Border!.Thickness.Left; + locationOffset.Y += SuperView.Border!.Thickness.Top; } int cx = me.Position.X - locationOffset.X; diff --git a/Terminal.Gui/Views/Shortcut.cs b/Terminal.Gui/Views/Shortcut.cs index e4fee2f2a..ccccc01bb 100644 --- a/Terminal.Gui/Views/Shortcut.cs +++ b/Terminal.Gui/Views/Shortcut.cs @@ -210,14 +210,14 @@ public class Shortcut : View, IOrientation, IDesignable case 0: case 1: // Scrunch it by removing both margins - HelpView.Margin.Thickness = new (t.Right - 1, t.Top, t.Left - 1, t.Bottom); + HelpView.Margin!.Thickness = new (t.Right - 1, t.Top, t.Left - 1, t.Bottom); break; case 2: // Scrunch just the right margin - HelpView.Margin.Thickness = new (t.Right, t.Top, t.Left - 1, t.Bottom); + HelpView.Margin!.Thickness = new (t.Right, t.Top, t.Left - 1, t.Bottom); break; } @@ -225,7 +225,7 @@ public class Shortcut : View, IOrientation, IDesignable else { // Reset to default - HelpView.Margin.Thickness = GetMarginThickness (); + HelpView.Margin!.Thickness = GetMarginThickness (); } } @@ -471,9 +471,9 @@ public class Shortcut : View, IOrientation, IDesignable { if (CommandView.Margin is { }) { - CommandView.Margin.Thickness = GetMarginThickness (); + CommandView.Margin!.Thickness = GetMarginThickness (); // strip off ViewportSettings.TransparentMouse - CommandView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; + CommandView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; } CommandView.X = Pos.Align (Alignment.End, AlignmentModes); @@ -533,9 +533,9 @@ public class Shortcut : View, IOrientation, IDesignable { if (HelpView.Margin is { }) { - HelpView.Margin.Thickness = GetMarginThickness (); + HelpView.Margin!.Thickness = GetMarginThickness (); // strip off ViewportSettings.TransparentMouse - HelpView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; + HelpView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; } HelpView.X = Pos.Align (Alignment.End, AlignmentModes); @@ -666,9 +666,9 @@ public class Shortcut : View, IOrientation, IDesignable { if (KeyView.Margin is { }) { - KeyView.Margin.Thickness = GetMarginThickness (); + KeyView.Margin!.Thickness = GetMarginThickness (); // strip off ViewportSettings.TransparentMouse - KeyView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; + KeyView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse; } KeyView.X = Pos.Align (Alignment.End, AlignmentModes); diff --git a/Terminal.Gui/Views/StatusBar.cs b/Terminal.Gui/Views/StatusBar.cs index 9be738c7d..3d58a7afc 100644 --- a/Terminal.Gui/Views/StatusBar.cs +++ b/Terminal.Gui/Views/StatusBar.cs @@ -71,7 +71,7 @@ public class StatusBar : Bar, IDesignable if (barItem.Border is { }) { - barItem.Border.Thickness = index == SubViews.Count - 1 ? new Thickness (0, 0, 0, 0) : new Thickness (0, 0, 1, 0); + barItem.Border!.Thickness = index == SubViews.Count - 1 ? new Thickness (0, 0, 0, 0) : new Thickness (0, 0, 1, 0); } if (barItem is Shortcut shortcut) diff --git a/Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs b/Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs index 11dd5d811..f082807c6 100644 --- a/Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs +++ b/Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs @@ -61,7 +61,7 @@ public class NetMaskedTextProvider : ITextValidateProvider public bool Fixed => true; /// - public string DisplayText => _provider.ToDisplayString (); + public string DisplayText => _provider!.ToDisplayString (); /// public int Cursor (int pos) diff --git a/Terminal.Gui/Views/TreeView/Branch.cs b/Terminal.Gui/Views/TreeView/Branch.cs index 59b0475a6..811824dbf 100644 --- a/Terminal.Gui/Views/TreeView/Branch.cs +++ b/Terminal.Gui/Views/TreeView/Branch.cs @@ -451,7 +451,6 @@ internal class Branch where T : class /// Returns true if the given x offset on the branch line is the +/- symbol. Returns false if not showing /// expansion symbols or leaf node etc. /// - /// /// /// internal bool IsHitOnExpandableSymbol (int x) diff --git a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs index 65a8f3a70..3485ecf08 100644 --- a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs +++ b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs @@ -16,11 +16,11 @@ public class FakeApplicationFactory var cts = new CancellationTokenSource (); var fakeInput = new FakeNetInput (cts.Token); FakeOutput output = new (); - output.Size = new (25, 25); + output.Size = new (80, 25); IApplication origApp = ApplicationImpl.Instance; - var sizeMonitor = new FakeSizeMonitor (); + var sizeMonitor = new FakeSizeMonitor (output, output.LastBuffer!); var impl = new ApplicationImpl (new FakeNetComponentFactory (fakeInput, output, sizeMonitor)); @@ -32,13 +32,13 @@ public class FakeApplicationFactory // Handle different facade types - cast to common interface instead var d = (IConsoleDriverFacade)Application.Driver!; - sizeMonitor.SizeChanging += (_, e) => + sizeMonitor.SizeChanged += (_, e) => { if (e.Size != null) { Size s = e.Size.Value; output.Size = s; - d.OutputBuffer.SetWindowSize (s.Width, s.Height); + d.OutputBuffer.SetSize (s.Width, s.Height); } }; diff --git a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeConsoleDriver.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeConsoleDriver.cs deleted file mode 100644 index 4b42dee78..000000000 --- a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeConsoleDriver.cs +++ /dev/null @@ -1,58 +0,0 @@ -#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; - -/// -/// Implementation of that uses fake input/output. -/// This is a lightweight alternative to (if you don't -/// need the entire application main loop running). -/// -internal class FakeConsoleDriver : ConsoleDriverFacade, IFakeConsoleDriver -{ - internal FakeConsoleDriver ( - ConcurrentQueue inputBuffer, - OutputBuffer outputBuffer, - FakeOutput fakeOutput, - Func 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 InputBuffer { get; } - public new OutputBuffer OutputBuffer { get; } - public FakeSizeMonitor SizeMonitor { get; } -} \ No newline at end of file diff --git a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeDriverFactory.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeDriverFactory.cs deleted file mode 100644 index 793b3362e..000000000 --- a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeDriverFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable enable -namespace Terminal.Gui.Drivers; - -#pragma warning disable CS1591 -public class FakeDriverFactory -{ - /// - /// Creates a new instance of using default options - /// - /// - public IFakeConsoleDriver Create () - { - return new FakeConsoleDriver ( - new (), - new (), - new (), - () => DateTime.Now, - new ()); - } -} diff --git a/Tests/TerminalGuiFluentTesting/FakeInput.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeInput.cs similarity index 100% rename from Tests/TerminalGuiFluentTesting/FakeInput.cs rename to Tests/TerminalGuiFluentTesting/FakeDriver/FakeInput.cs diff --git a/Tests/TerminalGuiFluentTesting/FakeOutput.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeOutput.cs similarity index 83% rename from Tests/TerminalGuiFluentTesting/FakeOutput.cs rename to Tests/TerminalGuiFluentTesting/FakeDriver/FakeOutput.cs index 9f747e8f7..00b8bd1b7 100644 --- a/Tests/TerminalGuiFluentTesting/FakeOutput.cs +++ b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeOutput.cs @@ -17,7 +17,7 @@ internal class FakeOutput : IConsoleOutput public void Write (IOutputBuffer buffer) { LastBuffer = buffer; } /// - public Size GetWindowSize () { return Size; } + public Size GetSize () { return Size; } /// public void SetCursorVisibility (CursorVisibility visibility) { } @@ -25,6 +25,12 @@ internal class FakeOutput : IConsoleOutput /// public void SetCursorPosition (int col, int row) { CursorPosition = new Point (col, row); } + /// + public void SetSize (int width, int height) + { + Size = new (width, height); + } + /// /// The last value set by calling /// diff --git a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs index 2c4a982e9..cd2ac4f77 100644 --- a/Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs +++ b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs @@ -4,17 +4,17 @@ using System.Drawing; namespace Terminal.Gui.Drivers; #pragma warning disable CS1591 -public class FakeSizeMonitor : IWindowSizeMonitor +public class FakeSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer _) : IConsoleSizeMonitor { - /// - public event EventHandler? SizeChanging; + /// + public event EventHandler? SizeChanged; /// public bool Poll () { return false; } /// - /// Raises the event. + /// Raises the event. /// /// - public void RaiseSizeChanging (Size newSize) { SizeChanging?.Invoke (this, new (newSize)); } -} + public void RaiseSizeChanged (Size newSize) { SizeChanged?.Invoke (this, new (newSize)); } +} \ No newline at end of file diff --git a/Tests/TerminalGuiFluentTesting/FakeWindowsInput.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/FakeWindowsInput.cs similarity index 100% rename from Tests/TerminalGuiFluentTesting/FakeWindowsInput.cs rename to Tests/TerminalGuiFluentTesting/FakeDriver/FakeWindowsInput.cs diff --git a/Tests/TerminalGuiFluentTesting/FakeDriver/IFakeConsoleDriver.cs b/Tests/TerminalGuiFluentTesting/FakeDriver/IFakeConsoleDriver.cs deleted file mode 100644 index b0186cb2e..000000000 --- a/Tests/TerminalGuiFluentTesting/FakeDriver/IFakeConsoleDriver.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable enable -namespace Terminal.Gui.Drivers; - -#pragma warning disable CS1591 -public interface IFakeConsoleDriver : IConsoleDriver, IConsoleDriverFacade -{ - void SetBufferSize (int width, int height); -} diff --git a/Tests/TerminalGuiFluentTesting/GuiTestContext.cs b/Tests/TerminalGuiFluentTesting/GuiTestContext.cs index 9bec9caf0..754ac4886 100644 --- a/Tests/TerminalGuiFluentTesting/GuiTestContext.cs +++ b/Tests/TerminalGuiFluentTesting/GuiTestContext.cs @@ -43,7 +43,7 @@ public class GuiTestContext : IDisposable _winInput = new (_cts.Token); _output.Size = new (width, height); - _fakeSizeMonitor = new (); + _fakeSizeMonitor = new (_output, _output.LastBuffer!); IComponentFactory cf = driver == TestDriver.DotNet ? new FakeNetComponentFactory (_netInput, _output, _fakeSizeMonitor) @@ -238,11 +238,7 @@ public class GuiTestContext : IDisposable return WaitIteration ( () => { - _output.Size = new (width, height); - _fakeSizeMonitor.RaiseSizeChanging (_output.Size); - - var d = (IConsoleDriverFacade)Application.Driver!; - d.OutputBuffer.SetWindowSize (width, height); + Application.Driver!.SetScreenSize(width, height); }); } @@ -938,48 +934,35 @@ public class GuiTestContext : IDisposable public Point GetCursorPosition () { return _output.CursorPosition; } } -internal class FakeWindowsComponentFactory : WindowsComponentFactory +internal class FakeWindowsComponentFactory (FakeWindowsInput winInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor) + : WindowsComponentFactory { - private readonly FakeWindowsInput _winInput; - private readonly FakeOutput _output; - private readonly FakeSizeMonitor _fakeSizeMonitor; + /// + public override IConsoleInput CreateInput () { return winInput; } - public FakeWindowsComponentFactory (FakeWindowsInput winInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor) + /// + public override IConsoleOutput CreateOutput () { return output; } + + /// + public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { - _winInput = winInput; - _output = output; - _fakeSizeMonitor = fakeSizeMonitor; + outputBuffer.SetSize (consoleOutput.GetSize ().Width, consoleOutput.GetSize ().Height); + return fakeSizeMonitor; } - - /// - public override IConsoleInput CreateInput () { return _winInput; } - - /// - public override IConsoleOutput CreateOutput () { return _output; } - - /// - public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { return _fakeSizeMonitor; } } -internal class FakeNetComponentFactory : NetComponentFactory +internal class FakeNetComponentFactory (FakeNetInput netInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor) : NetComponentFactory { - private readonly FakeNetInput _netInput; - private readonly FakeOutput _output; - private readonly FakeSizeMonitor _fakeSizeMonitor; + /// + public override IConsoleInput CreateInput () { return netInput; } - public FakeNetComponentFactory (FakeNetInput netInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor) + /// + public override IConsoleOutput CreateOutput () { return output; } + + /// + public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { - _netInput = netInput; - _output = output; - _fakeSizeMonitor = fakeSizeMonitor; + outputBuffer.SetSize (consoleOutput.GetSize ().Width, consoleOutput.GetSize ().Height); + return fakeSizeMonitor; } - - /// - public override IConsoleInput CreateInput () { return _netInput; } - - /// - public override IConsoleOutput CreateOutput () { return _output; } - - /// - public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { return _fakeSizeMonitor; } } diff --git a/Tests/UnitTests/Application/Application.NavigationTests.cs b/Tests/UnitTests/Application/Application.NavigationTests.cs index cc61f8643..03f7b9235 100644 --- a/Tests/UnitTests/Application/Application.NavigationTests.cs +++ b/Tests/UnitTests/Application/Application.NavigationTests.cs @@ -1,7 +1,7 @@ using UnitTests; using Xunit.Abstractions; -namespace UnitTests.ApplicationTests.NavigationTests; +namespace UnitTests.ApplicationTests; public class ApplicationNavigationTests (ITestOutputHelper output) { diff --git a/Tests/UnitTests/Application/ApplicationImplTests.cs b/Tests/UnitTests/Application/ApplicationImplTests.cs index c04b6dfad..b0e41bf37 100644 --- a/Tests/UnitTests/Application/ApplicationImplTests.cs +++ b/Tests/UnitTests/Application/ApplicationImplTests.cs @@ -25,7 +25,7 @@ public class ApplicationImplTests m.Setup (f => f.CreateInput ()).Returns (netInput.Object); m.Setup (f => f.CreateInputProcessor (It.IsAny> ())).Returns (Mock.Of ()); m.Setup (f => f.CreateOutput ()).Returns (Mock.Of ()); - m.Setup (f => f.CreateWindowSizeMonitor (It.IsAny (),It.IsAny ())).Returns (Mock.Of ()); + m.Setup (f => f.CreateConsoleSizeMonitor (It.IsAny (),It.IsAny ())).Returns (Mock.Of ()); return new (m.Object); } @@ -38,7 +38,7 @@ public class ApplicationImplTests m.Setup (f => f.CreateInput ()).Returns (winInput.Object); m.Setup (f => f.CreateInputProcessor (It.IsAny> ())).Returns (Mock.Of ()); m.Setup (f => f.CreateOutput ()).Returns (Mock.Of ()); - m.Setup (f => f.CreateWindowSizeMonitor (It.IsAny (), It.IsAny ())).Returns (Mock.Of ()); + m.Setup (f => f.CreateConsoleSizeMonitor (It.IsAny (), It.IsAny ())).Returns (Mock.Of ()); return new (m.Object); } } diff --git a/Tests/UnitTests/Application/ApplicationPopoverTests.cs b/Tests/UnitTests/Application/ApplicationPopoverTests.cs index 53a0e4651..c068a3723 100644 --- a/Tests/UnitTests/Application/ApplicationPopoverTests.cs +++ b/Tests/UnitTests/Application/ApplicationPopoverTests.cs @@ -1,4 +1,5 @@ -namespace UnitTests.ApplicationTests; +#nullable enable +namespace UnitTests.ApplicationTests; public class ApplicationPopoverTests { @@ -276,7 +277,7 @@ public class ApplicationPopoverTests public PopoverTestClass () { CanFocus = true; - AddCommand (Command.New, NewCommandHandler); + AddCommand (Command.New, NewCommandHandler!); HotKeyBindings.Add (Key.N.WithCtrl, Command.New); return; diff --git a/Tests/UnitTests/Application/ApplicationScreenTests.cs b/Tests/UnitTests/Application/ApplicationScreenTests.cs index 4fb8b03d9..0e7cac0c4 100644 --- a/Tests/UnitTests/Application/ApplicationScreenTests.cs +++ b/Tests/UnitTests/Application/ApplicationScreenTests.cs @@ -89,7 +89,7 @@ public class ApplicationScreenTests } [Fact] - public void Screen_Changes_OnSizeChanged_Without_Call_Application_Init () + public void Screen_Changes_OnScreenChanged_Without_Call_Application_Init () { // Arrange Application.ResetState (true); @@ -99,7 +99,7 @@ public class ApplicationScreenTests Assert.Equal (new (0, 0, 25, 25), Application.Screen); // Act - ((FakeDriver)Application.Driver)!.SetBufferSize (120, 30); + Application.Driver.SetScreenSize(120,30); // Assert Assert.Equal (new (0, 0, 120, 30), Application.Screen); diff --git a/Tests/UnitTests/Application/ApplicationTests.cs b/Tests/UnitTests/Application/ApplicationTests.cs index 8de8b43b5..56e39c1aa 100644 --- a/Tests/UnitTests/Application/ApplicationTests.cs +++ b/Tests/UnitTests/Application/ApplicationTests.cs @@ -1,8 +1,4 @@ using System.Diagnostics; -using System.Reflection; -using JetBrains.Annotations; -using Terminal.Gui.Drivers; -using UnitTests; using Xunit.Abstractions; using static Terminal.Gui.Configuration.ConfigurationManager; @@ -81,8 +77,8 @@ public class ApplicationTests _timeoutLock = null; } - a.After (null); + return; void OnApplicationOnInitializedChanged (object s, EventArgs a) @@ -167,11 +163,11 @@ public class ApplicationTests public void Begin_Sets_Application_Top_To_Console_Size () { Assert.Null (Application.Top); - AutoInitShutdownAttribute.FakeResize (new Size (80, 25)); + Application.Driver!.SetScreenSize (80, 25); Toplevel top = new (); Application.Begin (top); Assert.Equal (new (0, 0, 80, 25), Application.Top!.Frame); - AutoInitShutdownAttribute.FakeResize (new Size (5, 5)); + Application.Driver!.SetScreenSize (5, 5); Assert.Equal (new (0, 0, 5, 5), Application.Top!.Frame); top.Dispose (); } @@ -212,7 +208,7 @@ public class ApplicationTests public void Init_Begin_End_Cleans_Up () { // Start stopwatch - Stopwatch stopwatch = new Stopwatch (); + var stopwatch = new Stopwatch (); stopwatch.Start (); // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests @@ -252,7 +248,6 @@ public class ApplicationTests stopwatch.Stop (); _output.WriteLine ($"Load took {stopwatch.ElapsedMilliseconds} ms"); - } // Legacy driver test - all InlineData commented out @@ -284,6 +279,7 @@ public class ApplicationTests [Theory] [InlineData (typeof (FakeDriver))] + //[InlineData (typeof (DotNetDriver))] //[InlineData (typeof (WindowsDriver))] //[InlineData (typeof (UnixDriver))] @@ -422,6 +418,7 @@ public class ApplicationTests [Theory] [InlineData (typeof (FakeDriver))] + //[InlineData (typeof (DotNetDriver))] //[InlineData (typeof (WindowsDriver))] //[InlineData (typeof (UnixDriver))] @@ -461,11 +458,8 @@ public class ApplicationTests [AutoInitShutdown] public void Init_Unbalanced_Throws () { - Assert.Throws ( - () => - Application.InternalInit ( - new FakeDriver () - ) + Assert.Throws (() => + Application.Init (null, "fake") ); Application.Shutdown (); @@ -473,7 +467,6 @@ public class ApplicationTests Assert.Null (Application.Driver); } - [Fact] [AutoInitShutdown] public void Init_Unbalanced_Throws2 () @@ -496,7 +489,7 @@ public class ApplicationTests // NOTE: Run, when called after Init has been called behaves differently than // when called if Init has not been called. Toplevel topLevel = new (); - Application.InternalInit (new FakeDriver ()); + Application.Init (null, "fake"); RunState runstate = null; @@ -532,6 +525,7 @@ public class ApplicationTests { Application.ForceDriver = "Fake"; Application.Init (); + //Assert.IsType(Application.Drive); //Assert.IsType (Application.Driver); Application.ResetState (); @@ -556,7 +550,7 @@ public class ApplicationTests } finally { - Application.ResetState (false); + Application.ResetState (); } } @@ -594,7 +588,7 @@ public class ApplicationTests { var iteration = 0; - Application.Init (null, driverName: "fake"); + Application.Init (null, "fake"); Application.Iteration += Application_Iteration; Application.Run ().Dispose (); @@ -620,9 +614,9 @@ public class ApplicationTests [AutoInitShutdown] public void Screen_Size_Changes () { - var driver = Application.Driver; + IConsoleDriver driver = Application.Driver; - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); + Application.Driver!.SetScreenSize (80, 25); Assert.Equal (new (0, 0, 80, 25), driver.Screen); Assert.Equal (new (0, 0, 80, 25), Application.Screen); @@ -630,13 +624,14 @@ public class ApplicationTests // TODO: Should not be possible to manually change these at whim! driver.Cols = 100; driver.Rows = 30; + // IConsoleDriver.Screen isn't assignable //driver.Screen = new (0, 0, driver.Cols, Rows); - AutoInitShutdownAttribute.FakeResize (new Size (100, 30)); + Application.Driver!.SetScreenSize (100, 30); Assert.Equal (new (0, 0, 100, 30), driver.Screen); - + // Assert does not make sense // Assert.NotEqual (new (0, 0, 100, 30), Application.Screen); // Assert.Equal (new (0, 0, 80, 25), Application.Screen); @@ -647,11 +642,7 @@ public class ApplicationTests } [Fact] - public void InitState_Throws_If_Driver_Is_Null () - { - Assert.Throws (static () => Application.SubscribeDriverEvents ()); - } - + public void InitState_Throws_If_Driver_Is_Null () { Assert.Throws (static () => Application.SubscribeDriverEvents ()); } #region RunTests @@ -701,7 +692,6 @@ public class ApplicationTests [TestRespondersDisposed] public void Run_T_After_Init_Does_Not_Disposes_Application_Top () { - // Init doesn't create a Toplevel and assigned it to Application.Top // but Begin does var initTop = new Toplevel (); @@ -785,7 +775,7 @@ public class ApplicationTests Assert.Null (Application.Driver); } - [Fact(Skip = "FakeDriver is not allowed, use AutoInitShutdown attribute instead")] + [Fact (Skip = "FakeDriver is not allowed, use AutoInitShutdown attribute instead")] [TestRespondersDisposed] public void Run_T_NoInit_DoesNotThrow () { @@ -907,7 +897,7 @@ public class ApplicationTests Width = 5, Height = 5, Arrangement = ViewArrangement.Movable }; - AutoInitShutdownAttribute.FakeResize (new Size (10, 10)); + Application.Driver!.SetScreenSize (10, 10); RunState rs = Application.Begin (w); // Don't use visuals to test as style of border can change over time. @@ -1075,7 +1065,8 @@ public class ApplicationTests Assert.Null (Application.Top); } - private class TestToplevel : Toplevel { } + private class TestToplevel : Toplevel + { } private readonly object _forceDriverLock = new (); @@ -1155,19 +1146,15 @@ public class ApplicationTests 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 ()); + + 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); diff --git a/Tests/UnitTests/Application/TimedEventsTests.cs b/Tests/UnitTests/Application/TimedEventsTests.cs index e03c027c7..4877a6b2c 100644 --- a/Tests/UnitTests/Application/TimedEventsTests.cs +++ b/Tests/UnitTests/Application/TimedEventsTests.cs @@ -1,42 +1,50 @@ -using System.Diagnostics; - +#nullable enable namespace UnitTests.ApplicationTests; /// -/// Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch. +/// Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch. /// public class TimedEventsTests { [Fact] public void HighFrequency_Concurrent_Invocations_No_Lost_Timeouts () { - var timedEvents = new Terminal.Gui.App.TimedEvents (); + var timedEvents = new TimedEvents (); var counter = 0; var expected = 1000; var completed = new ManualResetEventSlim (false); // Add many timeouts with TimeSpan.Zero concurrently - Parallel.For (0, expected, i => - { - timedEvents.Add (TimeSpan.Zero, () => - { - var current = Interlocked.Increment (ref counter); - if (current == expected) - { - completed.Set (); - } - return false; // One-shot - }); - }); + Parallel.For ( + 0, + expected, + i => + { + timedEvents.Add ( + TimeSpan.Zero, + () => + { + int current = Interlocked.Increment (ref counter); + + if (current == expected) + { + completed.Set (); + } + + return false; // One-shot + }); + }); // Run timers multiple times to ensure all are processed - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { timedEvents.RunTimers (); + if (completed.IsSet) { break; } + Thread.Sleep (10); } @@ -46,51 +54,52 @@ public class TimedEventsTests [Fact] public void GetTimestampTicks_Provides_High_Resolution () { - var timedEvents = new Terminal.Gui.App.TimedEvents (); - + var timedEvents = new TimedEvents (); + // Add multiple timeouts with TimeSpan.Zero rapidly - var timestamps = new List (); - + List timestamps = new (); + // Single event handler to capture all timestamps - EventHandler? handler = null; - handler = (s, e) => - { - timestamps.Add (e.Ticks); - }; - + EventHandler? handler = null; + handler = (s, e) => { timestamps.Add (e.Ticks); }; + timedEvents.Added += handler; - - for (int i = 0; i < 100; i++) + + for (var i = 0; i < 100; i++) { timedEvents.Add (TimeSpan.Zero, () => false); } - + timedEvents.Added -= handler; // Verify that we got timestamps Assert.True (timestamps.Count > 0, $"Should have captured timestamps. Got {timestamps.Count}"); - + // Verify that we got unique timestamps (or very close) // With Stopwatch, we should have much better resolution than DateTime.UtcNow - var uniqueTimestamps = timestamps.Distinct ().Count (); - + int uniqueTimestamps = timestamps.Distinct ().Count (); + // We should have mostly unique timestamps // Allow some duplicates due to extreme speed, but should be > 50% unique - Assert.True (uniqueTimestamps > timestamps.Count / 2, - $"Expected more unique timestamps. Got {uniqueTimestamps} unique out of {timestamps.Count} total"); + Assert.True ( + uniqueTimestamps > timestamps.Count / 2, + $"Expected more unique timestamps. Got {uniqueTimestamps} unique out of {timestamps.Count} total"); } [Fact] public void TimeSpan_Zero_Executes_Immediately () { - var timedEvents = new Terminal.Gui.App.TimedEvents (); + var timedEvents = new TimedEvents (); var executed = false; - timedEvents.Add (TimeSpan.Zero, () => - { - executed = true; - return false; - }); + timedEvents.Add ( + TimeSpan.Zero, + () => + { + executed = true; + + return false; + }); Assert.True (timedEvents.Timeouts.Keys [0] > 0); @@ -104,17 +113,20 @@ public class TimedEventsTests [Fact] public void Multiple_TimeSpan_Zero_Timeouts_All_Execute () { - var timedEvents = new Terminal.Gui.App.TimedEvents (); + var timedEvents = new TimedEvents (); var executeCount = 0; var expected = 100; - for (int i = 0; i < expected; i++) + for (var i = 0; i < expected; i++) { - timedEvents.Add (TimeSpan.Zero, () => - { - Interlocked.Increment (ref executeCount); - return false; - }); + timedEvents.Add ( + TimeSpan.Zero, + () => + { + Interlocked.Increment (ref executeCount); + + return false; + }); } // Run timers once diff --git a/Tests/UnitTests/AutoInitShutdownAttribute.cs b/Tests/UnitTests/AutoInitShutdownAttribute.cs index b5e11ccbc..6361e1545 100644 --- a/Tests/UnitTests/AutoInitShutdownAttribute.cs +++ b/Tests/UnitTests/AutoInitShutdownAttribute.cs @@ -26,7 +26,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute /// is true. /// /// - /// If true, will force the use of . Only valid if + /// If true, will force the use of . Only valid if /// == and is true. /// /// @@ -107,7 +107,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute Debug.Assert (!CM.IsEnabled, "This test left ConfigurationManager enabled!"); // Force the ConfigurationManager to reset to its hardcoded defaults - CM.Disable(true); + CM.Disable (true); } public override void Before (MethodInfo methodUnderTest) @@ -138,12 +138,14 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute #endif if (_driverType == null) { - Application.Top = null; - Application.TopLevels.Clear (); + //Application.Init (null, "fake"); + //Application.Driver!.SetScreenSize (80, 25); + //Application.Top = null; + //Application.TopLevels.Clear (); var fa = new FakeApplicationFactory (); _v2Cleanup = fa.SetupFakeApplication (); - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); + //Application.Driver!.SetScreenSize (80,25)); } else { @@ -154,35 +156,12 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute private bool AutoInit { get; } - /// - /// 'Resizes' the application and forces layout. Only works if your test uses - /// - /// - public static void FakeResize (Size size) - { - var d = (IConsoleDriverFacade)Application.Driver!; - d.OutputBuffer.SetWindowSize (size.Width, size.Height); - - // Handle both FakeSizeMonitor (from test project) and FakeWindowSizeMonitor (from main library) - if (d.WindowSizeMonitor is FakeSizeMonitor fakeSizeMonitor) - { - fakeSizeMonitor.RaiseSizeChanging (size); - } - else if (d.WindowSizeMonitor is FakeWindowSizeMonitor fakeWindowSizeMonitor) - { - // For FakeWindowSizeMonitor, use the RaiseSizeChanging method - fakeWindowSizeMonitor.RaiseSizeChanging (size); - } - - Application.LayoutAndDraw (true); - } - /// /// Runs a single iteration of the main loop (layout, draw, run timed events etc.) /// public static void RunIteration () { - var a = (ApplicationImpl)ApplicationImpl.Instance; + ApplicationImpl a = (ApplicationImpl)ApplicationImpl.Instance; a.Coordinator?.RunIteration (); } } \ No newline at end of file diff --git a/Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs b/Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs index 3cc5433c5..73cee1d11 100644 --- a/Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs @@ -15,119 +15,96 @@ public class ClipRegionTests this._output = output; } - [Theory] - [InlineData (typeof (FakeDriver))] - //[InlineData (typeof (DotNetDriver))] - - //[InlineData (typeof (ANSIDriver))] - //[InlineData (typeof (WindowsDriver))] - //[InlineData (typeof (UnixDriver))] - public void AddRune_Is_Clipped (Type driverType) + [Fact] + public void AddRune_Is_Clipped () { - var driver = (IConsoleDriver)Activator.CreateInstance (driverType); - Application.Init (driver); - Application.Driver!.Rows = 25; - Application.Driver!.Cols = 80; + Application.Init (null, "fake"); - driver.Move (0, 0); - driver.AddRune ('x'); - Assert.Equal ((Rune)'x', driver.Contents [0, 0].Rune); + Application.Driver!.Move (0, 0); + Application.Driver!.AddRune ('x'); + Assert.Equal ((Rune)'x', Application.Driver!.Contents! [0, 0].Rune); - driver.Move (5, 5); - driver.AddRune ('x'); - Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune); + Application.Driver?.Move (5, 5); + Application.Driver?.AddRune ('x'); + Assert.Equal ((Rune)'x', Application.Driver!.Contents [5, 5].Rune); // Clear the contents - driver.FillRect (new Rectangle (0, 0, driver.Rows, driver.Cols), ' '); - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); + Application.Driver?.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), ' '); + Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune); // Setup the region with a single rectangle, fill screen with 'x' - driver.Clip = new (new Rectangle (5, 5, 5, 5)); - driver.FillRect (new Rectangle (0, 0, driver.Rows, driver.Cols), 'x'); - Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune); - Assert.Equal ((Rune)' ', driver.Contents [4, 9].Rune); - Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune); - Assert.Equal ((Rune)'x', driver.Contents [9, 9].Rune); - Assert.Equal ((Rune)' ', driver.Contents [10, 10].Rune); + Application.Driver!.Clip = new (new Rectangle (5, 5, 5, 5)); + Application.Driver.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), 'x'); + Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune); + Assert.Equal ((Rune)' ', Application.Driver?.Contents [4, 9].Rune); + Assert.Equal ((Rune)'x', Application.Driver?.Contents [5, 5].Rune); + Assert.Equal ((Rune)'x', Application.Driver?.Contents [9, 9].Rune); + Assert.Equal ((Rune)' ', Application.Driver?.Contents [10, 10].Rune); Application.Shutdown (); } - [Theory] - [InlineData (typeof (FakeDriver))] - //[InlineData (typeof (DotNetDriver))] - - //[InlineData (typeof (ANSIDriver))] - //[InlineData (typeof (WindowsDriver))] - //[InlineData (typeof (UnixDriver))] - public void Clip_Set_To_Empty_AllInvalid (Type driverType) + [Fact] + public void Clip_Set_To_Empty_AllInvalid () { - var driver = (IConsoleDriver)Activator.CreateInstance (driverType); - Application.Init (driver); + Application.Init (null, "fake"); // Define a clip rectangle - driver.Clip = new (Rectangle.Empty); + Application.Driver!.Clip = new (Rectangle.Empty); // negative - Assert.False (driver.IsValidLocation (default, 4, 5)); - Assert.False (driver.IsValidLocation (default, 5, 4)); - Assert.False (driver.IsValidLocation (default, 10, 9)); - Assert.False (driver.IsValidLocation (default, 9, 10)); - Assert.False (driver.IsValidLocation (default, -1, 0)); - Assert.False (driver.IsValidLocation (default, 0, -1)); - Assert.False (driver.IsValidLocation (default, -1, -1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows)); + Assert.False (Application.Driver.IsValidLocation (default, 4, 5)); + Assert.False (Application.Driver.IsValidLocation (default, 5, 4)); + Assert.False (Application.Driver.IsValidLocation (default, 10, 9)); + Assert.False (Application.Driver.IsValidLocation (default, 9, 10)); + Assert.False (Application.Driver.IsValidLocation (default, -1, 0)); + Assert.False (Application.Driver.IsValidLocation (default, 0, -1)); + Assert.False (Application.Driver.IsValidLocation (default, -1, -1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows)); Application.Shutdown (); } - [Theory] - [InlineData (typeof (FakeDriver))] - //[InlineData (typeof (DotNetDriver))] - - //[InlineData (typeof (ANSIDriver))] - //[InlineData (typeof (WindowsDriver))] - //[InlineData (typeof (UnixDriver))] - public void IsValidLocation (Type driverType) + [Fact] + public void IsValidLocation () { - var driver = (IConsoleDriver)Activator.CreateInstance (driverType); - Application.Init (driver); + Application.Init (null, "fake"); Application.Driver!.Rows = 10; Application.Driver!.Cols = 10; // positive - Assert.True (driver.IsValidLocation (default, 0, 0)); - Assert.True (driver.IsValidLocation (default, 1, 1)); - Assert.True (driver.IsValidLocation (default, driver.Cols - 1, driver.Rows - 1)); + Assert.True (Application.Driver.IsValidLocation (default, 0, 0)); + Assert.True (Application.Driver.IsValidLocation (default, 1, 1)); + Assert.True (Application.Driver.IsValidLocation (default, Application.Driver.Cols - 1, Application.Driver.Rows - 1)); // negative - Assert.False (driver.IsValidLocation (default, -1, 0)); - Assert.False (driver.IsValidLocation (default, 0, -1)); - Assert.False (driver.IsValidLocation (default, -1, -1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows)); + Assert.False (Application.Driver.IsValidLocation (default, -1, 0)); + Assert.False (Application.Driver.IsValidLocation (default, 0, -1)); + Assert.False (Application.Driver.IsValidLocation (default, -1, -1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows)); // Define a clip rectangle - driver.Clip = new(new Rectangle(5, 5, 5, 5)); + Application.Driver.Clip = new (new Rectangle (5, 5, 5, 5)); // positive - Assert.True (driver.IsValidLocation (default, 5, 5)); - Assert.True (driver.IsValidLocation (default, 9, 9)); + Assert.True (Application.Driver.IsValidLocation (default, 5, 5)); + Assert.True (Application.Driver.IsValidLocation (default, 9, 9)); // negative - Assert.False (driver.IsValidLocation (default, 4, 5)); - Assert.False (driver.IsValidLocation (default, 5, 4)); - Assert.False (driver.IsValidLocation (default, 10, 9)); - Assert.False (driver.IsValidLocation (default, 9, 10)); - Assert.False (driver.IsValidLocation (default, -1, 0)); - Assert.False (driver.IsValidLocation (default, 0, -1)); - Assert.False (driver.IsValidLocation (default, -1, -1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1)); - Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows)); + Assert.False (Application.Driver.IsValidLocation (default, 4, 5)); + Assert.False (Application.Driver.IsValidLocation (default, 5, 4)); + Assert.False (Application.Driver.IsValidLocation (default, 10, 9)); + Assert.False (Application.Driver.IsValidLocation (default, 9, 10)); + Assert.False (Application.Driver.IsValidLocation (default, -1, 0)); + Assert.False (Application.Driver.IsValidLocation (default, 0, -1)); + Assert.False (Application.Driver.IsValidLocation (default, -1, -1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1)); + Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows)); Application.Shutdown (); } diff --git a/Tests/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs b/Tests/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs index b77a1905a..8cfdcf1e8 100644 --- a/Tests/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/ConsoleDriverTests.cs @@ -160,7 +160,7 @@ public class ConsoleDriverTests // { // var win = new Window (); // Application.Begin (win); - // AutoInitShutdownAttribute.FakeResize(new Size ( (20, 8); + // Application.Driver!.SetScreenSize ( (20, 8); // System.Threading.Tasks.Task.Run (() => { // System.Threading.Tasks.Task.Delay (500).Wait (); diff --git a/Tests/UnitTests/ConsoleDrivers/EscSeqUtilsTests.cs b/Tests/UnitTests/ConsoleDrivers/EscSeqUtilsTests.cs new file mode 100644 index 000000000..21d59bcbc --- /dev/null +++ b/Tests/UnitTests/ConsoleDrivers/EscSeqUtilsTests.cs @@ -0,0 +1,106 @@ +using System.Text; + +// ReSharper disable HeuristicUnreachableCode + +namespace UnitTests.DriverTests; + +public class EscSeqUtilsTests +{ + [Fact] + public void Defaults_Values () + { + Assert.Equal ('\x1b', EscSeqUtils.KeyEsc); + Assert.Equal ("\x1b[", EscSeqUtils.CSI); + Assert.Equal ("\x1b[?1003h", EscSeqUtils.CSI_EnableAnyEventMouse); + Assert.Equal ("\x1b[?1006h", EscSeqUtils.CSI_EnableSgrExtModeMouse); + Assert.Equal ("\x1b[?1015h", EscSeqUtils.CSI_EnableUrxvtExtModeMouse); + Assert.Equal ("\x1b[?1003l", EscSeqUtils.CSI_DisableAnyEventMouse); + Assert.Equal ("\x1b[?1006l", EscSeqUtils.CSI_DisableSgrExtModeMouse); + Assert.Equal ("\x1b[?1015l", EscSeqUtils.CSI_DisableUrxvtExtModeMouse); + Assert.Equal ("\x1b[?1003h\x1b[?1015h\u001b[?1006h", EscSeqUtils.CSI_EnableMouseEvents); + Assert.Equal ("\x1b[?1003l\x1b[?1015l\u001b[?1006l", EscSeqUtils.CSI_DisableMouseEvents); + } + + [Fact] + public void GetConsoleInputKey_ConsoleKeyInfo () + { + var cki = new ConsoleKeyInfo ('r', 0, false, false, false); + var expectedCki = new ConsoleKeyInfo ('r', ConsoleKey.R, false, false, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, true, false, false); + expectedCki = new ('r', ConsoleKey.R, true, false, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, false, true, false); + expectedCki = new ('r', ConsoleKey.R, false, true, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, false, false, true); + expectedCki = new ('r', ConsoleKey.R, false, false, true); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, true, true, false); + expectedCki = new ('r', ConsoleKey.R, true, true, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, false, true, true); + expectedCki = new ('r', ConsoleKey.R, false, true, true); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('r', 0, true, true, true); + expectedCki = new ('r', ConsoleKey.R, true, true, true); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('\u0012', 0, false, false, false); + expectedCki = new ('\u0012', ConsoleKey.R, false, false, true); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('\0', (ConsoleKey)64, false, false, true); + expectedCki = new ('\0', ConsoleKey.Spacebar, false, false, true); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('\r', 0, false, false, false); + expectedCki = new ('\r', ConsoleKey.Enter, false, false, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('\u007f', 0, false, false, false); + expectedCki = new ('\u007f', ConsoleKey.Backspace, false, false, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + + cki = new ('R', 0, false, false, false); + expectedCki = new ('R', ConsoleKey.R, true, false, false); + Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); + } + + [Theory] + [InlineData (0, 0, $"{EscSeqUtils.CSI}0;0H")] + [InlineData (int.MaxValue, int.MaxValue, $"{EscSeqUtils.CSI}2147483647;2147483647H")] + [InlineData (int.MinValue, int.MinValue, $"{EscSeqUtils.CSI}-2147483648;-2147483648H")] + public void CSI_WriteCursorPosition_ReturnsCorrectEscSeq (int row, int col, string expected) + { + StringBuilder builder = new(); + using StringWriter writer = new(builder); + + EscSeqUtils.CSI_WriteCursorPosition (writer, row, col); + + string actual = builder.ToString(); + Assert.Equal (expected, actual); + } + + [Theory] + [InlineData ('\u001B', KeyCode.Esc)] + [InlineData ('\r', KeyCode.Enter)] + [InlineData ('1', KeyCode.D1)] + [InlineData ('!', (KeyCode)'!')] + [InlineData ('a', KeyCode.A)] + [InlineData ('A', KeyCode.A | KeyCode.ShiftMask)] + public void MapChar_Returns_Modifiers_If_Needed (char ch, KeyCode keyCode) + { + ConsoleKeyInfo cki = EscSeqUtils.MapChar (ch); + Key key = EscSeqUtils.MapKey (cki); + Key expectedKey = keyCode; + + Assert.Equal (key, expectedKey); + } +} diff --git a/Tests/UnitTests/ConsoleDrivers/FakeDriverTests.cs b/Tests/UnitTests/ConsoleDrivers/FakeDriverTests.cs index 4314492d4..c79145227 100644 --- a/Tests/UnitTests/ConsoleDrivers/FakeDriverTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/FakeDriverTests.cs @@ -1,12 +1,10 @@ -using UnitTests; -using Xunit; - +using System.Text; using Xunit.Abstractions; namespace UnitTests.DriverTests; /// -/// Tests for the FakeDriver to ensure it works properly with the modern component factory architecture. +/// Tests for the FakeDriver to ensure it works properly with the modern component factory architecture. /// public class FakeDriverTests (ITestOutputHelper output) { @@ -20,12 +18,13 @@ public class FakeDriverTests (ITestOutputHelper output) { // Verify Application was initialized Assert.True (Application.Initialized); - // Assert.NotNull (Application.Top); - + + // Assert.NotNull (Application.Top); + // Verify it's using a driver facade (modern architecture) Assert.IsAssignableFrom (Application.Driver); - - _output.WriteLine ($"Driver type: {Application.Driver.GetType().Name}"); + + _output.WriteLine ($"Driver type: {Application.Driver.GetType ().Name}"); _output.WriteLine ($"Screen size: {Application.Screen}"); } @@ -48,7 +47,7 @@ public class FakeDriverTests (ITestOutputHelper output) Assert.Equal (25, Application.Driver.Rows); // Resize to 100x30 - AutoInitShutdownAttribute.FakeResize (new (100, 30)); + Application.Driver?.SetScreenSize (100, 30); // Verify new size Assert.Equal (100, Application.Driver.Cols); @@ -60,7 +59,7 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Top_Is_Created () { - Application.Top = new Toplevel (); + Application.Top = new (); Application.Begin (Application.Top); @@ -73,7 +72,7 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Can_Add_View_To_Top () { - Application.Top = new Toplevel (); + Application.Top = new (); var label = new Label { Text = "Hello World" }; Application.Top!.Add (label); @@ -86,12 +85,11 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_RunIteration_Works () { - Application.Top = new Toplevel (); + Application.Top = new (); var label = new Label { Text = "Hello" }; Application.Top!.Add (label); - Application.Begin (Application.Top); // Run a single iteration - this should layout and draw @@ -106,43 +104,43 @@ public class FakeDriverTests (ITestOutputHelper output) #region AutoInitShutdown Attribute Tests - [Theory] - [InlineData (true)] - [InlineData (false)] - public void AutoInitShutdown_Attribute_Respects_AutoInit_Parameter (bool autoInit) - { - // When autoInit is false, Application should not be initialized - // When autoInit is true, Application should be initialized - - // This test will be called twice - once with autoInit=true, once with false - // We can't use the attribute directly in the test body, but we can verify - // the behavior by checking Application.Initialized - - // For this test to work properly, we need to call Application.Init manually when autoInit=false - bool wasInitialized = Application.Initialized; - - try - { - if (!wasInitialized) - { - Application.ResetState (); - var fa = new FakeApplicationFactory (); - using var cleanup = fa.SetupFakeApplication (); - Assert.True (Application.Initialized); - } - else - { - Assert.True (Application.Initialized); - } - } - finally - { - if (!wasInitialized) - { - Application.Shutdown (); - } - } - } + //[Theory] + //[InlineData (true)] + //[InlineData (false)] + //public void AutoInitShutdown_Attribute_Respects_AutoInit_Parameter (bool autoInit) + //{ + // // When autoInit is false, Application should not be initialized + // // When autoInit is true, Application should be initialized + + // // This test will be called twice - once with autoInit=true, once with false + // // We can't use the attribute directly in the test body, but we can verify + // // the behavior by checking Application.Initialized + + // // For this test to work properly, we need to call Application.Init manually when autoInit=false + // bool wasInitialized = Application.Initialized; + + // try + // { + // if (!wasInitialized) + // { + // Application.ResetState (); + // var fa = new FakeApplicationFactory (); + // using IDisposable cleanup = fa.SetupFakeApplication (); + // Assert.True (Application.Initialized); + // } + // else + // { + // Assert.True (Application.Initialized); + // } + // } + // finally + // { + // if (!wasInitialized) + // { + // Application.Shutdown (); + // } + // } + //} [Fact] public void Without_AutoInitShutdown_Application_Is_Not_Initialized () @@ -180,24 +178,24 @@ public class FakeDriverTests (ITestOutputHelper output) [Fact] [SetupFakeDriver] - public void SetupFakeDriver_Driver_Is_FakeConsoleDriver () + public void SetupFakeDriver_Driver_Is_IConsoleDriver () { Assert.NotNull (Application.Driver); - - // Should be IFakeConsoleDriver - Assert.IsAssignableFrom (Application.Driver); - - _output.WriteLine ($"Driver type: {Application.Driver.GetType().Name}"); + + // Should be IConsoleDriver + Assert.IsAssignableFrom (Application.Driver); + + _output.WriteLine ($"Driver type: {Application.Driver.GetType ().Name}"); } [Fact] [SetupFakeDriver] - public void SetupFakeDriver_Can_Set_Buffer_Size () + public void SetupFakeDriver_Can_Set_Screen_Size () { - var fakeDriver = Application.Driver as IFakeConsoleDriver; + IConsoleDriver fakeDriver = Application.Driver; Assert.NotNull (fakeDriver); - fakeDriver!.SetBufferSize (100, 50); + fakeDriver!.SetScreenSize (100, 50); Assert.Equal (100, Application.Driver!.Cols); Assert.Equal (50, Application.Driver.Rows); @@ -211,10 +209,10 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Can_Draw_Simple_View () { - Application.Top = new Toplevel (); + Application.Top = new (); - var window = new Window - { + var window = new Window + { Title = "Test Window", X = 0, Y = 0, @@ -222,13 +220,13 @@ public class FakeDriverTests (ITestOutputHelper output) Height = 10 }; - var label = new Label - { + var label = new Label + { Text = "Hello World", X = 1, Y = 1 }; - + window.Add (label); Application.Top!.Add (window); @@ -248,13 +246,13 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Multiple_RunIterations_Work () { - Application.Top = new Toplevel (); + Application.Top = new (); var label = new Label { Text = "Iteration Test" }; Application.Top!.Add (label); // Run multiple iterations - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { AutoInitShutdownAttribute.RunIteration (); } @@ -270,10 +268,10 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Resize_Triggers_Layout () { - Application.Top = new Toplevel (); + Application.Top = new (); - var view = new View - { + var view = new View + { Width = Dim.Fill (), Height = Dim.Fill () }; @@ -281,16 +279,15 @@ public class FakeDriverTests (ITestOutputHelper output) Application.Begin (Application.Top); - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); AutoInitShutdownAttribute.RunIteration (); // Check initial size - var initialFrame = view.Frame; + Rectangle initialFrame = view.Frame; Assert.Equal (80, initialFrame.Width); Assert.Equal (25, initialFrame.Height); // Resize - AutoInitShutdownAttribute.FakeResize (new (100, 40)); + Application.Driver?.SetScreenSize (100, 40); // Check new size Assert.Equal (100, view.Frame.Width); @@ -301,7 +298,7 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Window_Can_Be_Shown_And_Closed () { - Application.Top = new Toplevel (); + Application.Top = new (); var window = new Window { Title = "Test" }; Application.Top!.Add (window); @@ -346,8 +343,8 @@ public class FakeDriverTests (ITestOutputHelper output) Assert.NotNull (Application.Driver!.Clipboard); // Should throw NotSupportedException - Assert.Throws (() => - Application.Driver.Clipboard.GetClipboardData ()); + Assert.Throws (() => + Application.Driver.Clipboard.GetClipboardData ()); } #endregion @@ -358,11 +355,11 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Handles_Invalid_Coordinates_Gracefully () { - Application.Top = new Toplevel (); + Application.Top = new (); // Try to add a view with invalid coordinates - should not crash - var view = new View - { + var view = new View + { X = -1000, Y = -1000, Width = 10, @@ -370,10 +367,10 @@ public class FakeDriverTests (ITestOutputHelper output) }; Application.Top!.Add (view); - + // Should not throw AutoInitShutdownAttribute.RunIteration (); - + Assert.True (Application.Initialized); } @@ -381,8 +378,8 @@ public class FakeDriverTests (ITestOutputHelper output) [AutoInitShutdown] public void FakeDriver_Survives_Rapid_Resizes () { - var sizes = new[] - { + Size [] sizes = new [] + { new Size (80, 25), new Size (100, 30), new Size (60, 20), @@ -390,15 +387,155 @@ public class FakeDriverTests (ITestOutputHelper output) new Size (80, 25) }; - foreach (var size in sizes) + foreach (Size size in sizes) { - AutoInitShutdownAttribute.FakeResize (size); + Application.Driver!.SetScreenSize (size.Width, size.Height); AutoInitShutdownAttribute.RunIteration (); - + Assert.Equal (size.Width, Application.Driver!.Cols); Assert.Equal (size.Height, Application.Driver.Rows); } } #endregion + + #region Buffer and Fill Tests + + [Fact] + [AutoInitShutdown] + public void FakeDriver_Can_Fill_Rectangle () + { + // Verify driver is initialized with buffers + Assert.NotNull (Application.Driver); + Assert.NotNull (Application.Driver!.Contents); + + // Fill a rectangle + var rect = new Rectangle (5, 5, 10, 5); + Application.Driver.FillRect (rect, (Rune)'X'); + + // Verify the rectangle was filled + for (int row = rect.Y; row < rect.Y + rect.Height; row++) + { + for (int col = rect.X; col < rect.X + rect.Width; col++) + { + Assert.Equal ((Rune)'X', Application.Driver.Contents [row, col].Rune); + } + } + } + + [Fact] + [AutoInitShutdown] + public void FakeDriver_Buffer_Integrity_After_Multiple_Resizes () + { + // Start with default size + Assert.Equal (80, Application.Driver!.Cols); + Assert.Equal (25, Application.Driver.Rows); + + // Fill with a pattern + Application.Driver.FillRect (new (0, 0, 10, 5), (Rune)'A'); + + // Resize + Application.Driver?.SetScreenSize (100, 30); + + // Verify new size + Assert.Equal (100, Application.Driver.Cols); + Assert.Equal (30, Application.Driver.Rows); + + // Verify buffer is clean (no stale runes from previous size) + Assert.NotNull (Application.Driver.Contents); + Assert.Equal (30, Application.Driver.Contents!.GetLength (0)); + Assert.Equal (100, Application.Driver.Contents.GetLength (1)); + + // Fill with new pattern + Application.Driver.FillRect (new (0, 0, 20, 10), (Rune)'B'); + + // Resize back + Application.Driver?.SetScreenSize (80, 25); + + // Verify size is back + Assert.Equal (80, Application.Driver.Cols); + Assert.Equal (25, Application.Driver.Rows); + + // Verify buffer dimensions match + Assert.Equal (25, Application.Driver.Contents.GetLength (0)); + Assert.Equal (80, Application.Driver.Contents.GetLength (1)); + } + + #endregion + + #region ScreenChanged Event Tests + + [Fact] + [AutoInitShutdown] + public void ScreenChanged_Event_Fires_On_SetScreenSize () + { + var screenChangedFired = false; + Size? newSize = null; + + Application.Driver!.SizeChanged += (sender, args) => + { + screenChangedFired = true; + newSize = args.Size; + }; + + // Trigger resize using FakeResize which uses SetScreenSize internally + Application.Driver?.SetScreenSize (100, 30); + + // Verify event fired + Assert.True (screenChangedFired); + Assert.NotNull (newSize); + Assert.Equal (100, newSize!.Value.Width); + Assert.Equal (30, newSize.Value.Height); + } + + [Fact] + [AutoInitShutdown] + public void FakeResize_Triggers_ScreenChanged_And_Updates_Application_Screen () + { + var screenChangedFired = false; + Size? eventSize = null; + + Application.Driver!.SizeChanged += (sender, args) => + { + screenChangedFired = true; + eventSize = args.Size; + }; + + // Use FakeResize helper + Application.Driver?.SetScreenSize (120, 40); + + // Verify event fired + Assert.True (screenChangedFired); + Assert.NotNull (eventSize); + Assert.Equal (120, eventSize!.Value.Width); + Assert.Equal (40, eventSize.Value.Height); + + // Verify Application.Screen was updated + Assert.Equal (new (0, 0, 120, 40), Application.Screen); + Assert.Equal (120, Application.Driver.Cols); + Assert.Equal (40, Application.Driver.Rows); + } + + [Fact] + [AutoInitShutdown] + public void SizeChanged_Event_Still_Fires_For_Compatibility () + { + var sizeChangedFired = false; + var screenChangedFired = false; + +#pragma warning disable CS0618 // Type or member is obsolete + Application.Driver!.SizeChanged += (sender, args) => { sizeChangedFired = true; }; +#pragma warning restore CS0618 // Type or member is obsolete + + Application.Driver.SizeChanged += (sender, args) => { screenChangedFired = true; }; + + // Trigger resize using FakeResize + Application.Driver?.SetScreenSize (90, 35); + + // Both events should fire for compatibility + Assert.True (sizeChangedFired); + Assert.True (screenChangedFired); + } + + #endregion } diff --git a/Tests/UnitTests/ConsoleDrivers/WindowSizeMonitorTests.cs b/Tests/UnitTests/ConsoleDrivers/WindowSizeMonitorTests.cs index 1301087da..8753719b9 100644 --- a/Tests/UnitTests/ConsoleDrivers/WindowSizeMonitorTests.cs +++ b/Tests/UnitTests/ConsoleDrivers/WindowSizeMonitorTests.cs @@ -1,43 +1,41 @@ using Moq; namespace UnitTests.DriverTests; + public class WindowSizeMonitorTests { - public WindowSizeMonitorTests () - { - ConsoleDriver.RunningUnitTests = false; - } + public WindowSizeMonitorTests () { ConsoleDriver.RunningUnitTests = false; } [Fact] public void TestWindowSizeMonitor_RaisesEventWhenChanges () { - var consoleOutput = new Mock (); + Mock consoleOutput = new (); - var queue = new Queue(new []{ - new Size (30, 20), - new Size (20, 20) + Queue queue = new ( + [ + new (30, 20), + new (20, 20) + ]); - }); - - consoleOutput.Setup (m => m.GetWindowSize ()) + consoleOutput.Setup (m => m.GetSize ()) .Returns (queue.Dequeue); var outputBuffer = Mock.Of (); - var monitor = new WindowSizeMonitor (consoleOutput.Object, outputBuffer); + var monitor = new ConsoleSizeMonitor (consoleOutput.Object, outputBuffer); - var result = new List (); - monitor.SizeChanging += (s, e) => { result.Add (e);}; + List result = new (); + monitor.SizeChanged += (s, e) => { result.Add (e); }; Assert.Empty (result); monitor.Poll (); Assert.Single (result); - Assert.Equal (new Size (30,20),result [0].Size); + Assert.Equal (new Size (30, 20), result [0].Size); monitor.Poll (); - Assert.Equal (2,result.Count); + Assert.Equal (2, result.Count); Assert.Equal (new Size (30, 20), result [0].Size); Assert.Equal (new Size (20, 20), result [1].Size); } @@ -45,22 +43,24 @@ public class WindowSizeMonitorTests [Fact] public void TestWindowSizeMonitor_DoesNotRaiseEventWhen_NoChanges () { - var consoleOutput = new Mock (); + Mock consoleOutput = new (); - var queue = new Queue (new []{ - new Size (30, 20), - new Size (30, 20), - }); + Queue queue = new ( + new [] + { + new Size (30, 20), + new Size (30, 20) + }); - consoleOutput.Setup (m => m.GetWindowSize ()) + consoleOutput.Setup (m => m.GetSize ()) .Returns (queue.Dequeue); var outputBuffer = Mock.Of (); - var monitor = new WindowSizeMonitor (consoleOutput.Object, outputBuffer); + var monitor = new ConsoleSizeMonitor (consoleOutput.Object, outputBuffer); - var result = new List (); - monitor.SizeChanging += (s, e) => { result.Add (e); }; + List result = new (); + monitor.SizeChanged += (s, e) => { result.Add (e); }; // First poll always raises event because going from unknown size i.e. 0,0 Assert.Empty (result); diff --git a/Tests/UnitTests/Dialogs/DialogTests.cs b/Tests/UnitTests/Dialogs/DialogTests.cs index f3f008f9d..59a6de315 100644 --- a/Tests/UnitTests/Dialogs/DialogTests.cs +++ b/Tests/UnitTests/Dialogs/DialogTests.cs @@ -20,7 +20,7 @@ public class DialogTests (ITestOutputHelper output) // We test with one button first, but do this to get the width right for 2 int width = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}".Length; - AutoInitShutdownAttribute.FakeResize (new (width, 1)); + Driver?.SetScreenSize (width, 1); // Override CM Dialog.DefaultButtonAlignment = Alignment.Center; @@ -163,7 +163,7 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 3)); + Driver?.SetScreenSize (buttonRow.Length, 3); // Default - Center (runState, Dialog dlg) = BeginButtonTestDialog ( @@ -255,7 +255,7 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = string.Empty; var width = 30; - AutoInitShutdownAttribute.FakeResize (new (width, 1)); + Driver?.SetScreenSize (width, 1); // Default - Center buttonRow = @@ -351,7 +351,7 @@ public class DialogTests (ITestOutputHelper output) // 123456 1234567 var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 1)); + Driver?.SetScreenSize (buttonRow.Length, 1); // Default - Center (runState, Dialog dlg) = BeginButtonTestDialog ( @@ -446,7 +446,7 @@ public class DialogTests (ITestOutputHelper output) // 123456 123456 var buttonRow = $"{Glyphs.VLine} {btn1} {btn2} {btn3} {btn4} {Glyphs.VLine}"; int width = buttonRow.GetColumns (); - AutoInitShutdownAttribute.FakeResize (new (width, 3)); + Driver?.SetScreenSize (width, 3); // Default - Center (runState, Dialog dlg) = BeginButtonTestDialog ( @@ -531,7 +531,7 @@ public class DialogTests (ITestOutputHelper output) $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (width, 1)); + Driver?.SetScreenSize (width, 1); (runState, Dialog dlg) = BeginButtonTestDialog ( title, @@ -595,7 +595,7 @@ public class DialogTests (ITestOutputHelper output) $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}"; width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (width, 1)); + Driver?.SetScreenSize (width, 1); (runState, dlg) = BeginButtonTestDialog ( title, @@ -675,7 +675,7 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {btn3} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 3)); + Driver?.SetScreenSize (buttonRow.Length, 3); (runState, Dialog dlg) = BeginButtonTestDialog ( title, @@ -758,7 +758,7 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 3)); + Driver?.SetScreenSize (buttonRow.Length, 3); (runState, Dialog dlg) = BeginButtonTestDialog ( title, @@ -837,7 +837,7 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = $@"{Glyphs.VLine} {btn1} {btn2} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 3)); + Driver?.SetScreenSize (buttonRow.Length, 3); // Default (Center) Button button1 = new () { Text = btn1Text }; @@ -957,7 +957,7 @@ public class DialogTests (ITestOutputHelper output) [AutoInitShutdown] public void Dialog_In_Window_With_Size_One_Button_Aligns () { - AutoInitShutdownAttribute.FakeResize (new (20, 5)); + Driver?.SetScreenSize (20, 5); // Override CM Window.DefaultBorderStyle = LineStyle.Single; @@ -1062,7 +1062,7 @@ public class DialogTests (ITestOutputHelper output) )] public void Dialog_In_Window_Without_Size_One_Button_Aligns (int height, string expected) { - AutoInitShutdownAttribute.FakeResize (new (20, height)); + Driver?.SetScreenSize (20, height); var win = new Window (); int iterations = -1; @@ -1109,7 +1109,7 @@ public class DialogTests (ITestOutputHelper output) [AutoInitShutdown] public void Dialog_Opened_From_Another_Dialog () { - AutoInitShutdownAttribute.FakeResize (new (30, 10)); + Driver?.SetScreenSize (30, 10); // Override CM Dialog.DefaultButtonAlignment = Alignment.Center; @@ -1251,7 +1251,7 @@ public class DialogTests (ITestOutputHelper output) Height = Dim.Percent (85) }; Begin (d); - AutoInitShutdownAttribute.FakeResize (new (100, 100)); + Driver?.SetScreenSize (100, 100); // Default location is centered, so 100 / 2 - 85 / 2 = 7 var expected = 7; @@ -1265,7 +1265,7 @@ public class DialogTests (ITestOutputHelper output) { var d = new Dialog { X = 1, Y = 1 }; Begin (d); - AutoInitShutdownAttribute.FakeResize (new (100, 100)); + Driver?.SetScreenSize (100, 100); // Default location is centered, so 100 / 2 - 85 / 2 = 7 var expected = 1; @@ -1287,7 +1287,7 @@ public class DialogTests (ITestOutputHelper output) var expected = 5; var d = new Dialog { X = expected, Y = expected, Height = 5, Width = 5 }; Begin (d); - AutoInitShutdownAttribute.FakeResize (new (20, 10)); + Driver?.SetScreenSize (20, 10); // Default location is centered, so 100 / 2 - 85 / 2 = 7 Assert.Equal (new (expected, expected), d.Frame.Location); @@ -1321,7 +1321,7 @@ public class DialogTests (ITestOutputHelper output) Y = 1 }; - AutoInitShutdownAttribute.FakeResize (new (20, 20)); + Driver?.SetScreenSize (20, 20); var iterations = 0; @@ -1340,7 +1340,7 @@ public class DialogTests (ITestOutputHelper output) else if (iterations == 2) { // Mouse click outside of dialog - RaiseMouseEvent (new() { Flags = MouseFlags.Button1Clicked, ScreenPosition = new (0, 0) }); + RaiseMouseEvent (new () { Flags = MouseFlags.Button1Clicked, ScreenPosition = new (0, 0) }); } }; @@ -1370,7 +1370,7 @@ public class DialogTests (ITestOutputHelper output) $"{Glyphs.VLine} {Glyphs.LeftBracket} {btnText} {Glyphs.RightBracket} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 10)); + Driver?.SetScreenSize (buttonRow.Length, 10); (runState, Dialog dlg) = BeginButtonTestDialog ( title, @@ -1435,7 +1435,7 @@ public class DialogTests (ITestOutputHelper output) }; Begin (d); - AutoInitShutdownAttribute.FakeResize (new (100, 100)); + Driver?.SetScreenSize (100, 100); // Default size is Percent(85) Assert.Equal (new ((int)(100 * .85), (int)(100 * .85)), d.Frame.Size); @@ -1451,7 +1451,7 @@ public class DialogTests (ITestOutputHelper output) var d = new Dialog { Width = 50, Height = 50 }; Begin (d); - AutoInitShutdownAttribute.FakeResize (new (100, 100)); + Driver?.SetScreenSize (100, 100); // Default size is Percent(85) Assert.Equal (new (50, 50), d.Frame.Size); @@ -1468,9 +1468,9 @@ public class DialogTests (ITestOutputHelper output) var buttonRow = $"{Glyphs.VLine} {Glyphs.VLine}"; int width = buttonRow.Length; - AutoInitShutdownAttribute.FakeResize (new (buttonRow.Length, 3)); + Driver?.SetScreenSize (buttonRow.Length, 3); - (runState, Dialog dlg) = BeginButtonTestDialog (title, width, Alignment.Center, []); + (runState, Dialog dlg) = BeginButtonTestDialog (title, width, Alignment.Center); DriverAssert.AssertDriverContentsWithFrameAre ($"{buttonRow}", output); diff --git a/Tests/UnitTests/Dialogs/MessageBoxTests.cs b/Tests/UnitTests/Dialogs/MessageBoxTests.cs index a3033c998..0fd0954e5 100644 --- a/Tests/UnitTests/Dialogs/MessageBoxTests.cs +++ b/Tests/UnitTests/Dialogs/MessageBoxTests.cs @@ -155,7 +155,7 @@ public class MessageBoxTests { int iterations = -1; - AutoInitShutdownAttribute.FakeResize(new Size(15, 15)); // 15 x 15 gives us enough room for a button with one char (9x1) + Application.Driver!.SetScreenSize(15, 15); // 15 x 15 gives us enough room for a button with one char (9x1) Dialog.DefaultShadow = ShadowStyle.None; Button.DefaultShadow = ShadowStyle.None; @@ -189,7 +189,7 @@ public class MessageBoxTests int iterations = -1; var top = new Toplevel (); top.BorderStyle = LineStyle.None; - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize(20, 10); var btn = $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} btn {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}"; @@ -259,7 +259,7 @@ public class MessageBoxTests int iterations = -1; var top = new Toplevel (); top.BorderStyle = LineStyle.None; - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize (20, 10); var btn = $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} btn {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}"; @@ -343,7 +343,7 @@ public class MessageBoxTests public void Size_Not_Default_Message (int height, int width, string message) { int iterations = -1; - AutoInitShutdownAttribute.FakeResize(new Size(100, 100)); + Application.Driver!.SetScreenSize(100, 100); Application.Iteration += (s, a) => { @@ -380,7 +380,7 @@ public class MessageBoxTests public void Size_Not_Default_Message_Button (int height, int width, string message) { int iterations = -1; - AutoInitShutdownAttribute.FakeResize(new Size(100, 100)); + Application.Driver?.SetScreenSize(100, 100); Application.Iteration += (s, a) => { @@ -413,7 +413,7 @@ public class MessageBoxTests public void Size_Not_Default_No_Message (int height, int width) { int iterations = -1; - AutoInitShutdownAttribute.FakeResize(new Size(100, 100)); + Application.Driver?.SetScreenSize(100, 100); Application.Iteration += (s, a) => { @@ -442,7 +442,7 @@ public class MessageBoxTests public void UICatalog_AboutBox () { int iterations = -1; - AutoInitShutdownAttribute.FakeResize (new Size (70, 15)); + Application.Driver!.SetScreenSize (70, 15); // Override CM MessageBox.DefaultButtonAlignment = Alignment.End; diff --git a/Tests/UnitTests/Dialogs/WizardTests.cs b/Tests/UnitTests/Dialogs/WizardTests.cs index c85ae53be..edf8a1692 100644 --- a/Tests/UnitTests/Dialogs/WizardTests.cs +++ b/Tests/UnitTests/Dialogs/WizardTests.cs @@ -1,9 +1,6 @@ -using UnitTests; -using Xunit.Abstractions; +namespace UnitTests.DialogTests; -namespace UnitTests.DialogTests; - -public class WizardTests () +public class WizardTests { // =========== Wizard Tests [Fact] @@ -43,7 +40,7 @@ public class WizardTests () // Same test, but with two steps wizard = new (); - step1 = new() { Title = "step1" }; + step1 = new () { Title = "step1" }; wizard.AddStep (step1); WizardStep step2 = new () { Title = "step2" }; wizard.AddStep (step2); @@ -75,9 +72,9 @@ public class WizardTests () // Same test, but with two steps but the 1st one disabled wizard = new (); - step1 = new() { Title = "step1" }; + step1 = new () { Title = "step1" }; wizard.AddStep (step1); - step2 = new() { Title = "step2" }; + step2 = new () { Title = "step2" }; wizard.AddStep (step2); step1.Enabled = false; @@ -389,43 +386,22 @@ public class WizardTests () // and that the title is correct public void OneStepWizard_Shows () { - var title = "1234"; var stepTitle = "ABCD"; var width = 30; var height = 7; - AutoInitShutdownAttribute.FakeResize (new Size (width, height)); + Application.Driver?.SetScreenSize (width, height); // var btnBackText = "Back"; var btnBack = string.Empty; // $"{Glyphs.LeftBracket} {btnBackText} {Glyphs.RightBracket}"; var btnNextText = "Finish"; // "Next"; var btnNext = - $"{ - Glyphs.LeftBracket - }{ - Glyphs.LeftDefaultIndicator - } { - btnNextText - } { - Glyphs.RightDefaultIndicator - }{ - Glyphs.RightBracket - }"; + $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} {btnNextText} {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}"; var topRow = - $"{ - Glyphs.ULCornerDbl - }╡{ - title - } - { - stepTitle - }╞{ - new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 7) - }{ - Glyphs.URCornerDbl - }"; + $"{Glyphs.ULCornerDbl}╡{title} - {stepTitle}╞{new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 7)}{Glyphs.URCornerDbl}"; var row2 = $"{Glyphs.VLineDbl}{new (' ', width - 2)}{Glyphs.VLineDbl}"; string row3 = row2; string row4 = row3; @@ -434,29 +410,13 @@ public class WizardTests () $"{Glyphs.VLineDbl}{new (Glyphs.HLine.ToString () [0], width - 2)}{Glyphs.VLineDbl}"; var buttonRow = - $"{ - Glyphs.VLineDbl - }{ - btnBack - }{ - new (' ', width - btnBack.Length - btnNext.Length - 2) - }{ - btnNext - }{ - Glyphs.VLineDbl - }"; + $"{Glyphs.VLineDbl}{btnBack}{new (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{Glyphs.VLineDbl}"; var bottomRow = - $"{ - Glyphs.LLCornerDbl - }{ - new (Glyphs.HLineDbl.ToString () [0], width - 2) - }{ - Glyphs.LRCornerDbl - }"; + $"{Glyphs.LLCornerDbl}{new (Glyphs.HLineDbl.ToString () [0], width - 2)}{Glyphs.LRCornerDbl}"; Wizard wizard = new () { Title = title, Width = width, Height = height }; - wizard.AddStep (new() { Title = stepTitle }); + wizard.AddStep (new () { Title = stepTitle }); //wizard.LayoutSubViews (); RunState runstate = Application.Begin (wizard); @@ -477,42 +437,22 @@ public class WizardTests () // this test is needed because Wizard overrides Dialog's title behavior ("Title - StepTitle") public void Setting_Title_Works () { - var d = (IConsoleDriverFacade)Application.Driver; - + var d = Application.Driver; + var title = "1234"; var stepTitle = " - ABCD"; var width = 40; var height = 4; - d.OutputBuffer.SetWindowSize (width,height); + d.SetScreenSize (width, height); var btnNextText = "Finish"; var btnNext = - $"{ - Glyphs.LeftBracket - }{ - Glyphs.LeftDefaultIndicator - } { - btnNextText - } { - Glyphs.RightDefaultIndicator - }{ - Glyphs.RightBracket - }"; + $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} {btnNextText} {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}"; var topRow = - $"{ - Glyphs.ULCornerDbl - }╡{ - title - }{ - stepTitle - }╞{ - new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 4) - }{ - Glyphs.URCornerDbl - }"; + $"{Glyphs.ULCornerDbl}╡{title}{stepTitle}╞{new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 4)}{Glyphs.URCornerDbl}"; var separatorRow = $"{Glyphs.VLineDbl}{new (Glyphs.HLine.ToString () [0], width - 2)}{Glyphs.VLineDbl}"; @@ -523,16 +463,10 @@ public class WizardTests () //var buttonRow = $"{Glyphs.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{Glyphs.VDLine}"; var bottomRow = - $"{ - Glyphs.LLCornerDbl - }{ - new (Glyphs.HLineDbl.ToString () [0], width - 2) - }{ - Glyphs.LRCornerDbl - }"; + $"{Glyphs.LLCornerDbl}{new (Glyphs.HLineDbl.ToString () [0], width - 2)}{Glyphs.LRCornerDbl}"; var wizard = new Wizard { Title = title, Width = width, Height = height }; - wizard.AddStep (new() { Title = "ABCD" }); + wizard.AddStep (new () { Title = "ABCD" }); Application.End (Application.Begin (wizard)); wizard.Dispose (); @@ -646,37 +580,17 @@ public class WizardTests () var width = 30; var height = 6; - AutoInitShutdownAttribute.FakeResize (new Size (width, height)); + Application.Driver?.SetScreenSize (width, height); var btnBackText = "Back"; var btnBack = $"{Glyphs.LeftBracket} {btnBackText} {Glyphs.RightBracket}"; var btnNextText = "Finish"; var btnNext = - $"{ - Glyphs.LeftBracket - }{ - Glyphs.LeftDefaultIndicator - } { - btnNextText - } { - Glyphs.RightDefaultIndicator - }{ - Glyphs.RightBracket - }"; + $"{Glyphs.LeftBracket}{Glyphs.LeftDefaultIndicator} {btnNextText} {Glyphs.RightDefaultIndicator}{Glyphs.RightBracket}"; var topRow = - $"{ - Glyphs.ULCornerDbl - }╡{ - title - }{ - stepTitle - }╞{ - new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 4) - }{ - Glyphs.URCornerDbl - }"; + $"{Glyphs.ULCornerDbl}╡{title}{stepTitle}╞{new (Glyphs.HLineDbl.ToString () [0], width - title.Length - stepTitle.Length - 4)}{Glyphs.URCornerDbl}"; var row2 = $"{Glyphs.VLineDbl}{new (' ', width - 2)}{Glyphs.VLineDbl}"; string row3 = row2; @@ -684,26 +598,10 @@ public class WizardTests () $"{Glyphs.VLineDbl}{new (Glyphs.HLine.ToString () [0], width - 2)}{Glyphs.VLineDbl}"; var buttonRow = - $"{ - Glyphs.VLineDbl - }{ - btnBack - }{ - new (' ', width - btnBack.Length - btnNext.Length - 2) - }{ - btnNext - }{ - Glyphs.VLineDbl - }"; + $"{Glyphs.VLineDbl}{btnBack}{new (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{Glyphs.VLineDbl}"; var bottomRow = - $"{ - Glyphs.LLCornerDbl - }{ - new (Glyphs.HLineDbl.ToString () [0], width - 2) - }{ - Glyphs.LRCornerDbl - }"; + $"{Glyphs.LLCornerDbl}{new (Glyphs.HLineDbl.ToString () [0], width - 2)}{Glyphs.LRCornerDbl}"; var wizard = new Wizard { Title = title, Width = width, Height = height }; RunState runstate = Application.Begin (wizard); diff --git a/Tests/UnitTests/Drawing/LineCanvasTests.cs b/Tests/UnitTests/Drawing/LineCanvasTests.cs deleted file mode 100644 index 46f90658d..000000000 --- a/Tests/UnitTests/Drawing/LineCanvasTests.cs +++ /dev/null @@ -1,1263 +0,0 @@ -using System.Text; -using UnitTests; -using Xunit.Abstractions; - -namespace UnitTests.DrawingTests; - -public class LineCanvasTests (ITestOutputHelper output) -{ - [Theory] - - // Horizontal lines with a vertical zero-length - [InlineData ( - 0, - 0, - 1, - Orientation.Horizontal, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - "╞" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Horizontal, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - "╡" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Horizontal, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - "╟" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Horizontal, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - "╢" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Horizontal, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - "├" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Horizontal, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - "┤" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Horizontal, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - "╠" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Horizontal, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - "╣" - )] - - // Vertical lines with a horizontal zero-length - [InlineData ( - 0, - 0, - 1, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "╥" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "╨" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╤" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╧" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "┬" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "┴" - )] - [InlineData ( - 0, - 0, - 1, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╦" - )] - [InlineData ( - 0, - 0, - -1, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╩" - )] - - // Crosses (two zero-length) - [InlineData ( - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "╫" - )] - [InlineData ( - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╪" - )] - [InlineData ( - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Single, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Single, - "┼" - )] - [InlineData ( - 0, - 0, - 0, - Orientation.Vertical, - LineStyle.Double, - 0, - 0, - 0, - Orientation.Horizontal, - LineStyle.Double, - "╬" - )] - public void Add_2_Lines ( - int x1, - int y1, - int len1, - Orientation o1, - LineStyle s1, - int x2, - int y2, - int len2, - Orientation o2, - LineStyle s2, - string expected - ) - { - View v = GetCanvas (out LineCanvas lc); - v.Width = 10; - v.Height = 10; - v.Viewport = new (0, 0, 10, 10); - - lc.AddLine (new (x1, y1), len1, o1, s1); - lc.AddLine (new (x2, y2), len2, o2, s2); - - OutputAssert.AssertEqual (output, expected, lc.ToString ()); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void Viewport_Specific () - { - // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1) - // This proves we aren't drawing excess above - var x = 1; - var y = 2; - var width = 3; - var height = 2; - - var lc = new LineCanvas (); - - // 01230 - // ╔╡╞╗1 - // ║ ║2 - - // Add a short horiz line for ╔╡ - lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); - Assert.Equal (new (x, y, 2, 1), lc.Bounds); - - //LHS line down - lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); - Assert.Equal (new (x, y, 2, 2), lc.Bounds); - - //Vertical line before Title, results in a ╡ - lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); - Assert.Equal (new (x, y, 2, 2), lc.Bounds); - - //Vertical line after Title, results in a ╞ - lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); - Assert.Equal (new (x, y, 3, 2), lc.Bounds); - - // remainder of top line - lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); - Assert.Equal (new (x, y, 4, 2), lc.Bounds); - - //RHS line down - lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); - Assert.Equal (new (x, y, 4, 2), lc.Bounds); - - OutputAssert.AssertEqual ( - output, - @" -╔╡╞╗ -║ ║", - $"{Environment.NewLine}{lc}" - ); - } - - [Fact] - [SetupFakeDriver] - public void Viewport_Specific_With_Ustring () - { - // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1) - // This proves we aren't drawing excess above - var x = 1; - var y = 2; - var width = 3; - var height = 2; - - var lc = new LineCanvas (); - - // 01230 - // ╔╡╞╗1 - // ║ ║2 - - // Add a short horiz line for ╔╡ - lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); - Assert.Equal (new (x, y, 2, 1), lc.Bounds); - - //LHS line down - lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); - Assert.Equal (new (x, y, 2, 2), lc.Bounds); - - //Vertical line before Title, results in a ╡ - lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); - Assert.Equal (new (x, y, 2, 2), lc.Bounds); - - //Vertical line after Title, results in a ╞ - lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); - Assert.Equal (new (x, y, 3, 2), lc.Bounds); - - // remainder of top line - lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); - Assert.Equal (new (x, y, 4, 2), lc.Bounds); - - //RHS line down - lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); - Assert.Equal (new (x, y, 4, 2), lc.Bounds); - - OutputAssert.AssertEqual ( - output, - @" -╔╡╞╗ -║ ║", - $"{Environment.NewLine}{lc}" - ); - } - - [Fact] - [SetupFakeDriver] - public void Canvas_Updates_On_Changes () - { - var lc = new LineCanvas (); - - Assert.Equal (Rectangle.Empty, lc.Bounds); - - lc.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Double); - Assert.NotEqual (Rectangle.Empty, lc.Bounds); - - lc.Clear (); - Assert.Equal (Rectangle.Empty, lc.Bounds); - } - - [InlineData (0, 0, Orientation.Horizontal, "─")] - [InlineData (1, 0, Orientation.Horizontal, "─")] - [InlineData (0, 1, Orientation.Horizontal, "─")] - [InlineData (-1, 0, Orientation.Horizontal, "─")] - [InlineData (0, -1, Orientation.Horizontal, "─")] - [InlineData (-1, -1, Orientation.Horizontal, "─")] - [InlineData (0, 0, Orientation.Vertical, "│")] - [InlineData (1, 0, Orientation.Vertical, "│")] - [InlineData (0, 1, Orientation.Vertical, "│")] - [InlineData (0, -1, Orientation.Vertical, "│")] - [InlineData (-1, 0, Orientation.Vertical, "│")] - [InlineData (-1, -1, Orientation.Vertical, "│")] - [Theory] - [SetupFakeDriver] - public void Length_0_Is_1_Long (int x, int y, Orientation orientation, string expected) - { - var canvas = new LineCanvas (); - - // Add a line at 5, 5 that's has length of 1 - canvas.AddLine (new (x, y), 1, orientation, LineStyle.Single); - OutputAssert.AssertEqual (output, $"{expected}", $"{canvas}"); - } - - // X is offset by 2 - [InlineData (0, 0, 1, Orientation.Horizontal, "─")] - [InlineData (1, 0, 1, Orientation.Horizontal, "─")] - [InlineData (0, 1, 1, Orientation.Horizontal, "─")] - [InlineData (0, 0, 1, Orientation.Vertical, "│")] - [InlineData (1, 0, 1, Orientation.Vertical, "│")] - [InlineData (0, 1, 1, Orientation.Vertical, "│")] - [InlineData (-1, 0, 1, Orientation.Horizontal, "─")] - [InlineData (0, -1, 1, Orientation.Horizontal, "─")] - [InlineData (-1, 0, 1, Orientation.Vertical, "│")] - [InlineData (0, -1, 1, Orientation.Vertical, "│")] - [InlineData (0, 0, -1, Orientation.Horizontal, "─")] - [InlineData (1, 0, -1, Orientation.Horizontal, "─")] - [InlineData (0, 1, -1, Orientation.Horizontal, "─")] - [InlineData (0, 0, -1, Orientation.Vertical, "│")] - [InlineData (1, 0, -1, Orientation.Vertical, "│")] - [InlineData (0, 1, -1, Orientation.Vertical, "│")] - [InlineData (-1, 0, -1, Orientation.Horizontal, "─")] - [InlineData (0, -1, -1, Orientation.Horizontal, "─")] - [InlineData (-1, 0, -1, Orientation.Vertical, "│")] - [InlineData (0, -1, -1, Orientation.Vertical, "│")] - [InlineData (0, 0, 2, Orientation.Horizontal, "──")] - [InlineData (1, 0, 2, Orientation.Horizontal, "──")] - [InlineData (0, 1, 2, Orientation.Horizontal, "──")] - [InlineData (1, 1, 2, Orientation.Horizontal, "──")] - [InlineData (0, 0, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (1, 0, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (0, 1, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (1, 1, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (-1, 0, 2, Orientation.Horizontal, "──")] - [InlineData (0, -1, 2, Orientation.Horizontal, "──")] - [InlineData (-1, 0, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (0, -1, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (-1, -1, 2, Orientation.Vertical, "│\r\n│")] - [InlineData (0, 0, -2, Orientation.Horizontal, "──")] - [InlineData (1, 0, -2, Orientation.Horizontal, "──")] - [InlineData (0, 1, -2, Orientation.Horizontal, "──")] - [InlineData (0, 0, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (1, 0, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (0, 1, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (1, 1, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (-1, 0, -2, Orientation.Horizontal, "──")] - [InlineData (0, -1, -2, Orientation.Horizontal, "──")] - [InlineData (-1, 0, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (0, -1, -2, Orientation.Vertical, "│\r\n│")] - [InlineData (-1, -1, -2, Orientation.Vertical, "│\r\n│")] - [Theory] - [SetupFakeDriver] - public void Length_n_Is_n_Long (int x, int y, int length, Orientation orientation, string expected) - { - var canvas = new LineCanvas (); - canvas.AddLine (new (x, y), length, orientation, LineStyle.Single); - - var result = canvas.ToString (); - OutputAssert.AssertEqual (output, expected, result); - } - - [Fact] - [SetupFakeDriver] - public void Length_Negative () - { - var offset = new Point (5, 5); - - var canvas = new LineCanvas (); - canvas.AddLine (offset, -3, Orientation.Horizontal, LineStyle.Single); - - var looksLike = "───"; - - Assert.Equal (looksLike, $"{canvas}"); - } - - [InlineData (Orientation.Horizontal, "─")] - [InlineData (Orientation.Vertical, "│")] - [Theory] - [SetupFakeDriver] - public void Length_Zero_Alone_Is_Line (Orientation orientation, string expected) - { - var lc = new LineCanvas (); - - // Add a line at 0, 0 that's has length of 0 - lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); - OutputAssert.AssertEqual (output, expected, $"{lc}"); - } - - [InlineData (Orientation.Horizontal, "┼")] - [InlineData (Orientation.Vertical, "┼")] - [Theory] - [SetupFakeDriver] - public void Length_Zero_Cross_Is_Cross (Orientation orientation, string expected) - { - var lc = new LineCanvas (); - - // Add point at opposite orientation - lc.AddLine ( - Point.Empty, - 0, - orientation == Orientation.Horizontal ? Orientation.Vertical : Orientation.Horizontal, - LineStyle.Single - ); - - // Add a line at 0, 0 that's has length of 0 - lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); - OutputAssert.AssertEqual (output, expected, $"{lc}"); - } - - [InlineData (Orientation.Horizontal, "╥")] - [InlineData (Orientation.Vertical, "╞")] - [Theory] - [SetupFakeDriver] - public void Length_Zero_NextTo_Opposite_Is_T (Orientation orientation, string expected) - { - var lc = new LineCanvas (); - - // Add line with length of 1 in opposite orientation starting at same location - if (orientation == Orientation.Horizontal) - { - lc.AddLine (Point.Empty, 1, Orientation.Vertical, LineStyle.Double); - } - else - { - lc.AddLine (Point.Empty, 1, Orientation.Horizontal, LineStyle.Double); - } - - // Add a line at 0, 0 that's has length of 0 - lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); - OutputAssert.AssertEqual (output, expected, $"{lc}"); - } - - [Fact] - public void TestLineCanvas_LeaveMargin_Top1_Left1 () - { - var canvas = new LineCanvas (); - - // Upper box - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Single); - - var looksLike = - @" -┌─ -│ "; - OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); - } - - [Fact] - [SetupFakeDriver] - public void TestLineCanvas_Window_Heavy () - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Heavy); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Heavy); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Heavy); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Heavy); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy); - - v.Draw (); - - var looksLike = - @" -┏━━━━┳━━━┓ -┃ ┃ ┃ -┣━━━━╋━━━┫ -┃ ┃ ┃ -┗━━━━┻━━━┛"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Theory] - [SetupFakeDriver] - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - public void TestLineCanvas_Window_HeavyTop_ThinSides (LineStyle thinStyle) - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Heavy); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, thinStyle); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, thinStyle); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, thinStyle); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy); - - v.Draw (); - - var looksLike = - @" -┍━━━━┯━━━┑ -│ │ │ -┝━━━━┿━━━┥ -│ │ │ -┕━━━━┷━━━┙ -"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Theory] - [SetupFakeDriver] - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - public void TestLineCanvas_Window_ThinTop_HeavySides (LineStyle thinStyle) - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, thinStyle); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Heavy); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, thinStyle); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Heavy); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Heavy); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, thinStyle); - - v.Draw (); - - var looksLike = - @" -┎────┰───┒ -┃ ┃ ┃ -┠────╂───┨ -┃ ┃ ┃ -┖────┸───┚ - -"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void Top_Left_From_TopRight_LeftUp () - { - var canvas = new LineCanvas (); - - // Upper box - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (new (0, 1), -2, Orientation.Vertical, LineStyle.Single); - - var looksLike = - @" -┌─ -│ "; - OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); - } - - [Fact] - [SetupFakeDriver] - public void Top_With_1Down () - { - var canvas = new LineCanvas (); - - // Top ─ - canvas.AddLine (Point.Empty, 1, Orientation.Horizontal, LineStyle.Single); - - // Bottom ─ - canvas.AddLine (new (1, 1), -1, Orientation.Horizontal, LineStyle.Single); - - //// Right down - //canvas.AddLine (new Point (9, 0), 3, Orientation.Vertical, LineStyle.Single); - - //// Bottom - //canvas.AddLine (new Point (9, 3), -10, Orientation.Horizontal, LineStyle.Single); - - //// Left Up - //canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, LineStyle.Single); - - Assert.Equal (new (0, 0, 2, 2), canvas.Bounds); - - Dictionary map = canvas.GetMap (); - Assert.Equal (2, map.Count); - - OutputAssert.AssertEqual ( - output, - @" -─ - ─", - $"{Environment.NewLine}{canvas}" - ); - } - - [Fact] - [SetupFakeDriver] - public void ToString_Empty () - { - var lc = new LineCanvas (); - OutputAssert.AssertEqual (output, string.Empty, lc.ToString ()); - } - - // 012 - [InlineData (0, 0, "═══")] - [InlineData (1, 0, "═══")] - [InlineData (0, 1, "═══")] - [InlineData (1, 1, "═══")] - [InlineData (2, 2, "═══")] - [InlineData (-1, 0, "═══")] - [InlineData (0, -1, "═══")] - [InlineData (-1, -1, "═══")] - [InlineData (-2, -2, "═══")] - [Theory] - [SetupFakeDriver] - public void ToString_Positive_Horizontal_1Line_Offset (int x, int y, string expected) - { - var lc = new LineCanvas (); - lc.AddLine (new (x, y), 3, Orientation.Horizontal, LineStyle.Double); - OutputAssert.AssertEqual (output, expected, $"{lc}"); - } - - [InlineData (0, 0, 0, 0, "═══")] - [InlineData (1, 0, 1, 0, "═══")] - [InlineData (-1, 0, -1, 0, "═══")] - [InlineData (0, 0, 1, 0, "════")] - [InlineData (1, 0, 3, 0, "═════")] - [InlineData (1, 0, 4, 0, "══════")] - [InlineData (1, 0, 5, 0, "═══ ═══")] - [InlineData (0, 0, 0, 1, "\u2550\u2550\u2550\r\n\u2550\u2550\u2550")] - [InlineData (0, 0, 1, 1, "═══ \r\n ═══")] - [InlineData (0, 0, 2, 1, "═══ \r\n ═══")] - [InlineData (1, 0, 0, 1, " ═══\r\n═══ ")] - [InlineData (0, 1, 0, 1, "═══")] - [InlineData (1, 1, 0, 1, "════")] - [InlineData (2, 2, 0, 1, "═══ \r\n ═══")] - [Theory] - [SetupFakeDriver] - public void ToString_Positive_Horizontal_2Line_Offset (int x1, int y1, int x2, int y2, string expected) - { - var lc = new LineCanvas (); - lc.AddLine (new (x1, y1), 3, Orientation.Horizontal, LineStyle.Double); - lc.AddLine (new (x2, y2), 3, Orientation.Horizontal, LineStyle.Double); - - OutputAssert.AssertEqual (output, expected, $"{lc}"); - } - - // [Fact, SetupFakeDriver] - // public void LeaveMargin_Top1_Left1 () - // { - // var canvas = new LineCanvas (); - - // // Upper box - // canvas.AddLine (Point.Empty, 9, Orientation.Horizontal, LineStyle.Single); - // canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, LineStyle.Single); - // canvas.AddLine (new Point (8, 3), -9, Orientation.Horizontal, LineStyle.Single); - // canvas.AddLine (new Point (0, 2), -3, Orientation.Vertical, LineStyle.Single); - - // // Lower Box - // canvas.AddLine (new Point (5, 0), 2, Orientation.Vertical, LineStyle.Single); - // canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, LineStyle.Single); - - // string looksLike = - //@" - //┌────┬──┐ - //│ │ │ - //├────┼──┤ - //└────┴──┘ - //"; - // Assert.Equal (looksLike, $"{Environment.NewLine}{canvas}"); - // } - - [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, "═")] - [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, "║")] - [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, "─")] - [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, "│")] - [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, "═")] - [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Double, "║")] - [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, "─")] - [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Single, "│")] - [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Double, "══")] - [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Double, "║\n║")] - [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Single, "──")] - [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Single, "│\n│")] - [SetupFakeDriver] - [Theory] - public void View_Draws_1LineTests ( - int x1, - int y1, - int length, - Orientation o1, - LineStyle s1, - string expected - ) - { - View v = GetCanvas (out LineCanvas lc); - v.Width = 10; - v.Height = 10; - v.Viewport = new (0, 0, 10, 10); - - lc.AddLine (new (x1, y1), length, o1, s1); - - v.Draw (); - - DriverAssert.AssertDriverContentsAre (expected, output); - v.Dispose (); - } - - /// This test demonstrates how to correctly trigger a corner. By overlapping the lines in the same cell - [Fact] - [SetupFakeDriver] - public void View_Draws_Corner_Correct () - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Single); - - v.Draw (); - - var looksLike = - @" -┌─ -│"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - /// - /// This test demonstrates that corners are only drawn when lines overlap. Not when they terminate adjacent to one - /// another. - /// - [Fact] - [SetupFakeDriver] - public void View_Draws_Corner_NoOverlap () - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (new (0, 1), 2, Orientation.Vertical, LineStyle.Single); - - v.Draw (); - - var looksLike = - @" -── -│ -│"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - [Theory] - [SetupFakeDriver] - public void View_Draws_Horizontal (LineStyle style) - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, style); - - v.Draw (); - - var looksLike = - @" -──"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void View_Draws_Horizontal_Double () - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Double); - - v.Draw (); - - var looksLike = - @" -══"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - [Theory] - [SetupFakeDriver] - public void View_Draws_Vertical (LineStyle style) - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Vertical, style); - - v.Draw (); - - var looksLike = - @" -│ -│"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void View_Draws_Vertical_Double () - { - View v = GetCanvas (out LineCanvas canvas); - canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Double); - - v.Draw (); - - var looksLike = - @" -║ -║"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void View_Draws_Window_Double () - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Double); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Double); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Double); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Double); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Double); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Double); - - v.Draw (); - - var looksLike = - @" -╔════╦═══╗ -║ ║ ║ -╠════╬═══╣ -║ ║ ║ -╚════╩═══╝"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Theory] - [SetupFakeDriver] - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - public void View_Draws_Window_DoubleTop_SingleSides (LineStyle thinStyle) - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Double); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, thinStyle); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Double); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, thinStyle); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, thinStyle); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Double); - - v.Draw (); - - var looksLike = - @" -╒════╤═══╕ -│ │ │ -╞════╪═══╡ -│ │ │ -╘════╧═══╛ -"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - /// - /// Demonstrates when corners are used. Notice how not all lines declare rounded. - /// If there are 1+ lines intersecting and a corner is to be used then if any of them are rounded a rounded corner is - /// used. - /// - [Fact] - [SetupFakeDriver] - public void View_Draws_Window_Rounded () - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Rounded); - - // LineStyle.Single is ignored because corner overlaps with the above line which is Rounded - // this results in a rounded corner being used. - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Single); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Single); - - // These lines say rounded but they will result in the T sections which are never rounded. - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Rounded); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Rounded); - - v.Draw (); - - var looksLike = - @" -╭────┬───╮ -│ │ │ -├────┼───┤ -│ │ │ -╰────┴───╯"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Theory] - [InlineData (LineStyle.Single)] - [InlineData (LineStyle.Rounded)] - [SetupFakeDriver] - public void View_Draws_Window_SingleTop_DoubleSides (LineStyle thinStyle) - { - View v = GetCanvas (out LineCanvas canvas); - - // outer box - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, thinStyle); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Double); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, thinStyle); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Double); - - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Double); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, thinStyle); - - v.Draw (); - - var looksLike = - @" -╓────╥───╖ -║ ║ ║ -╟────╫───╢ -║ ║ ║ -╙────╨───╜ - -"; - DriverAssert.AssertDriverContentsAre (looksLike, output); - v.Dispose (); - } - - [Fact] - [SetupFakeDriver] - public void Window () - { - var canvas = new LineCanvas (); - - // Frame - canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Single); - canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Single); - canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Single); - - // Cross - canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Single); - canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Single); - - var looksLike = - @" -┌────┬───┐ -│ │ │ -├────┼───┤ -│ │ │ -└────┴───┘"; - OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); - } - - [Fact] - [SetupFakeDriver] - public void Zero_Length_Intersections () - { - // Draw at 1,2 within client area of View (i.e. leave a top and left margin of 1) - // This proves we aren't drawing excess above - var x = 1; - var y = 2; - var width = 5; - var height = 2; - - var lc = new LineCanvas (); - - // ╔╡╞═════╗ - // Add a short horiz line for ╔╡ - lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); - - //LHS line down - lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); - - //Vertical line before Title, results in a ╡ - lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); - - //Vertical line after Title, results in a ╞ - lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); - - // remainder of top line - lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); - - //RHS line down - lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); - - var looksLike = @" -╔╡╞══╗ -║ ║"; - OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{lc}"); - } - - [Fact] - public void LineCanvas_UsesFillCorrectly () - { - // Arrange - var foregroundColor = new Color (255, 0); // Red - var backgroundColor = new Color (0, 0); // Black - var foregroundFill = new SolidFill (foregroundColor); - var backgroundFill = new SolidFill (backgroundColor); - var fillPair = new FillPair (foregroundFill, backgroundFill); - - var lineCanvas = new LineCanvas - { - Fill = fillPair - }; - - // Act - lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); - Dictionary cellMap = lineCanvas.GetCellMap (); - - // Assert - foreach (Cell? cell in cellMap.Values) - { - Assert.NotNull (cell); - Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); - Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); - } - } - - [Fact] - public void LineCanvas_LineColorIgnoredBecauseOfFill () - { - // Arrange - var foregroundColor = new Color (255, 0); // Red - var backgroundColor = new Color (0, 0); // Black - var lineColor = new Attribute (new Color (0, 255), new Color (255, 255, 255)); // Green on White - var foregroundFill = new SolidFill (foregroundColor); - var backgroundFill = new SolidFill (backgroundColor); - var fillPair = new FillPair (foregroundFill, backgroundFill); - - var lineCanvas = new LineCanvas - { - Fill = fillPair - }; - - // Act - lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single, lineColor); - Dictionary cellMap = lineCanvas.GetCellMap (); - - // Assert - foreach (Cell? cell in cellMap.Values) - { - Assert.NotNull (cell); - Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); - Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); - } - } - - [Fact] - public void LineCanvas_IntersectingLinesUseFillCorrectly () - { - // Arrange - var foregroundColor = new Color (255, 0); // Red - var backgroundColor = new Color (0, 0); // Black - var foregroundFill = new SolidFill (foregroundColor); - var backgroundFill = new SolidFill (backgroundColor); - var fillPair = new FillPair (foregroundFill, backgroundFill); - - var lineCanvas = new LineCanvas - { - Fill = fillPair - }; - - // Act - lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); - lineCanvas.AddLine (new (2, -2), 5, Orientation.Vertical, LineStyle.Single); - Dictionary cellMap = lineCanvas.GetCellMap (); - - // Assert - foreach (Cell? cell in cellMap.Values) - { - Assert.NotNull (cell); - Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); - Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); - } - } - - // TODO: Remove this and make all LineCanvas tests independent of View - /// - /// Creates a new into which a is rendered at - /// time. - /// - /// The you can draw into. - /// How far to offset drawing in X - /// How far to offset drawing in Y - /// - private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0) - { - var v = new View { Width = 10, Height = 5, Viewport = new (0, 0, 10, 5) }; - - LineCanvas canvasCopy = canvas = new (); - - v.DrawComplete += (s, e) => - { - v.FillRect (v.Viewport); - - foreach (KeyValuePair p in canvasCopy.GetMap ()) - { - v.AddRune ( - offsetX + p.Key.X, - offsetY + p.Key.Y, - p.Value - ); - } - - canvasCopy.Clear (); - }; - - return v; - } -} diff --git a/Tests/UnitTests/Drawing/RulerTests.cs b/Tests/UnitTests/Drawing/RulerTests.cs deleted file mode 100644 index 00874d523..000000000 --- a/Tests/UnitTests/Drawing/RulerTests.cs +++ /dev/null @@ -1,142 +0,0 @@ -using UnitTests; -using Xunit.Abstractions; - -namespace UnitTests.DrawingTests; - -public class RulerTests -{ - private readonly ITestOutputHelper _output; - public RulerTests (ITestOutputHelper output) { _output = output; } - - [Fact] - [AutoInitShutdown] - public void Draw_Default () - { - AutoInitShutdownAttribute.FakeResize(new Size(25, 25)); - - var r = new Ruler (); - r.Draw (Point.Empty); - DriverAssert.AssertDriverContentsWithFrameAre (@"", _output); - } - - [Fact] - [SetupFakeDriver] - public void Draw_Horizontal () - { - var len = 15; - - var r = new Ruler (); - Assert.Equal (Orientation.Horizontal, r.Orientation); - - r.Length = len; - r.Draw (Point.Empty); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -|123456789|1234", - _output - ); - - // Postive offset - r.Draw (new (1, 1)); - - DriverAssert.AssertDriverContentsAre ( - @" -|123456789|1234 - |123456789|1234 -", - _output - ); - - // Negative offset - r.Draw (new (-1, 3)); - - DriverAssert.AssertDriverContentsAre ( - @" -|123456789|1234 - |123456789|1234 -123456789|1234 -", - _output - ); - } - - [Fact] - [SetupFakeDriver] - public void Draw_Vertical () - { - var len = 15; - - var r = new Ruler (); - r.Orientation = Orientation.Vertical; - r.Length = len; - r.Draw (Point.Empty); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -- -1 -2 -3 -4 -5 -6 -7 -8 -9 -- -1 -2 -3 -4", - _output - ); - - r.Draw (new (1, 1)); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -- -1- -21 -32 -43 -54 -65 -76 -87 -98 --9 -1- -21 -32 -43 - 4", - _output - ); - - // Negative offset - r.Draw (new (2, -1)); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -- 1 -1-2 -213 -324 -435 -546 -657 -768 -879 -98- --91 -1-2 -213 -324 -43 - 4 ", - _output - ); - } -} diff --git a/Tests/UnitTests/Drawing/ThicknessTests.cs b/Tests/UnitTests/Drawing/ThicknessTests.cs deleted file mode 100644 index 86bd32996..000000000 --- a/Tests/UnitTests/Drawing/ThicknessTests.cs +++ /dev/null @@ -1,255 +0,0 @@ -using System.Text; -using UnitTests; -using Xunit.Abstractions; - -namespace UnitTests.DrawingTests; - -public class ThicknessTests (ITestOutputHelper output) -{ - [Fact] - [AutoInitShutdown] - public void DrawTests () - { - AutoInitShutdownAttribute.FakeResize(new Size(60, 60)); - var t = new Thickness (0, 0, 0, 0); - var r = new Rectangle (5, 5, 40, 15); - - Application.Driver?.FillRect ( - new (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), - (Rune)' ' - ); - t.Draw (r, ViewDiagnosticFlags.Thickness, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" - Test (Left=0,Top=0,Right=0,Bottom=0)", - output - ); - - t = new (1, 1, 1, 1); - r = new (5, 5, 40, 15); - - Application.Driver?.FillRect ( - new (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), - (Rune)' ' - ); - t.Draw (r, ViewDiagnosticFlags.Thickness, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - T T - T T - T T - T T - T T - T T - T T - T T - T T - T T - T T - T T - T T - TTTest (Left=1,Top=1,Right=1,Bottom=1)TT", - output - ); - - t = new (1, 2, 3, 4); - r = new (5, 5, 40, 15); - - Application.Driver?.FillRect ( - new (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), - (Rune)' ' - ); - t.Draw (r, ViewDiagnosticFlags.Thickness, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - T TTT - T TTT - T TTT - T TTT - T TTT - T TTT - T TTT - T TTT - T TTT - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - TTTest (Left=1,Top=2,Right=3,Bottom=4)TT", - output - ); - - t = new (-1, 1, 1, 1); - r = new (5, 5, 40, 15); - - Application.Driver?.FillRect ( - new (0, 0, Application.Driver!.Cols, Application.Driver!.Rows), - (Rune)' ' - ); - t.Draw (r, ViewDiagnosticFlags.Thickness, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" - TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT - T - T - T - T - T - T - T - T - T - T - T - T - T - TTest (Left=-1,Top=1,Right=1,Bottom=1)TT", - output - ); - } - - [Fact] - [AutoInitShutdown] - public void DrawTests_Ruler () - { - // Add a frame so we can see the ruler - var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single}; - - var top = new Toplevel (); - top.Add (f); - RunState rs = Application.Begin (top); - - AutoInitShutdownAttribute.FakeResize(new Size(45, 20)); - var t = new Thickness (0, 0, 0, 0); - var r = new Rectangle (2, 2, 40, 15); - - AutoInitShutdownAttribute.RunIteration (); - - t.Draw (r, ViewDiagnosticFlags.Ruler, "Test"); - - DriverAssert.AssertDriverContentsAre ( - @" -┌───────────────────────────────────────────┐ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -└───────────────────────────────────────────┘", - output - ); - - t = new (1, 1, 1, 1); - r = new (1, 1, 40, 15); - top.SetNeedsDraw (); - AutoInitShutdownAttribute.RunIteration (); - t.Draw (r, ViewDiagnosticFlags.Ruler, "Test"); - - DriverAssert.AssertDriverContentsAre ( - @" -┌───────────────────────────────────────────┐ -│|123456789|123456789|123456789|123456789 │ -│1 1 │ -│2 2 │ -│3 3 │ -│4 4 │ -│5 5 │ -│6 6 │ -│7 7 │ -│8 8 │ -│9 9 │ -│- - │ -│1 1 │ -│2 2 │ -│3 3 │ -│|123456789|123456789|123456789|123456789 │ -│ │ -│ │ -│ │ -└───────────────────────────────────────────┘", - output - ); - - t = new (1, 2, 3, 4); - r = new (2, 2, 40, 15); - top.SetNeedsDraw (); - AutoInitShutdownAttribute.RunIteration (); - t.Draw (r, ViewDiagnosticFlags.Ruler, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -┌───────────────────────────────────────────┐ -│ │ -│ |123456789|123456789|123456789|123456789 │ -│ 1 1 │ -│ 2 2 │ -│ 3 3 │ -│ 4 4 │ -│ 5 5 │ -│ 6 6 │ -│ 7 7 │ -│ 8 8 │ -│ 9 9 │ -│ - - │ -│ 1 1 │ -│ 2 2 │ -│ 3 3 │ -│ |123456789|123456789|123456789|123456789 │ -│ │ -│ │ -└───────────────────────────────────────────┘", - output - ); - - t = new (-1, 1, 1, 1); - r = new (5, 5, 40, 15); - top.SetNeedsDraw (); - AutoInitShutdownAttribute.RunIteration (); - t.Draw (r, ViewDiagnosticFlags.Ruler, "Test"); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -┌───────────────────────────────────────────┐ -│ │ -│ │ -│ │ -│ │ -│ |123456789|123456789|123456789|123456789 -│ 1 -│ 2 -│ 3 -│ 4 -│ 5 -│ 6 -│ 7 -│ 8 -│ 9 -│ - -│ 1 -│ 2 -│ 3 -└────|123456789|123456789|123456789|123456789", - output - ); - top.Dispose (); - } -} diff --git a/Tests/UnitTests/DriverAssert.cs b/Tests/UnitTests/DriverAssert.cs index fe79a3fb3..d9e9e2184 100644 --- a/Tests/UnitTests/DriverAssert.cs +++ b/Tests/UnitTests/DriverAssert.cs @@ -1,4 +1,5 @@ -using System.Text; +#nullable enable +using System.Text; using System.Text.RegularExpressions; using Xunit.Abstractions; @@ -9,8 +10,9 @@ namespace UnitTests; /// internal partial class DriverAssert { - private const char SpaceChar = ' '; - private static readonly Rune SpaceRune = (Rune)SpaceChar; + private const char SPACE_CHAR = ' '; + private static readonly Rune _spaceRune = (Rune)SPACE_CHAR; + #pragma warning disable xUnit1013 // Public method should be marked as test /// /// Verifies are found at the locations specified by @@ -28,7 +30,7 @@ internal partial class DriverAssert public static void AssertDriverAttributesAre ( string expectedLook, ITestOutputHelper output, - IConsoleDriver driver = null, + IConsoleDriver? driver = null, params Attribute [] expectedAttributes ) { @@ -42,7 +44,7 @@ internal partial class DriverAssert expectedLook = expectedLook.Trim (); driver ??= Application.Driver; - Cell [,] contents = driver!.Contents; + Cell [,] contents = driver!.Contents!; var line = 0; @@ -107,7 +109,6 @@ internal partial class DriverAssert // // get the index of the actual attribute in `expectedAttributes` - // if (index == -1) // { // sb.Append ("x:x "); @@ -146,7 +147,7 @@ internal partial class DriverAssert public static void AssertDriverContentsAre ( string expectedLook, ITestOutputHelper output, - IConsoleDriver driver = null, + IConsoleDriver? driver = null, bool ignoreLeadingWhitespace = false ) { @@ -192,18 +193,19 @@ internal partial class DriverAssert public static Rectangle AssertDriverContentsWithFrameAre ( string expectedLook, ITestOutputHelper output, - IConsoleDriver driver = null + IConsoleDriver? driver = null ) { - List> lines = new (); + List> lines = []; var sb = new StringBuilder (); driver ??= Application.Driver; + int x = -1; int y = -1; int w = -1; int h = -1; - Cell [,] contents = driver.Contents; + Cell [,] contents = driver!.Contents!; for (var rowIndex = 0; rowIndex < driver.Rows; rowIndex++) { @@ -211,9 +213,9 @@ internal partial class DriverAssert for (var colIndex = 0; colIndex < driver.Cols; colIndex++) { - Rune runeAtCurrentLocation = contents [rowIndex, colIndex].Rune; + Rune runeAtCurrentLocation = contents! [rowIndex, colIndex].Rune; - if (runeAtCurrentLocation != SpaceRune) + if (runeAtCurrentLocation != _spaceRune) { if (x == -1) { @@ -222,7 +224,7 @@ internal partial class DriverAssert for (var i = 0; i < colIndex; i++) { - runes.InsertRange (i, [SpaceRune]); + runes.InsertRange (i, [_spaceRune]); } } @@ -330,7 +332,6 @@ internal partial class DriverAssert return new (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0); } - /// /// Verifies the console used all the when rendering. If one or more of the /// expected colors are not used then the failure will output both the colors that were found to be used and which of @@ -338,17 +339,17 @@ internal partial class DriverAssert /// /// if null uses /// - internal static void AssertDriverUsedColors (IConsoleDriver driver = null, params Attribute [] expectedColors) + internal static void AssertDriverUsedColors (IConsoleDriver? driver = null, params Attribute [] expectedColors) { driver ??= Application.Driver; - Cell [,] contents = driver.Contents; + Cell [,] contents = driver?.Contents!; List toFind = expectedColors.ToList (); // Contents 3rd column is an Attribute HashSet colorsUsed = new (); - for (var r = 0; r < driver.Rows; r++) + for (var r = 0; r < driver!.Rows; r++) { for (var c = 0; c < driver.Cols; c++) { @@ -381,11 +382,9 @@ internal partial class DriverAssert throw new (sb.ToString ()); } - [GeneratedRegex ("^\\s+", RegexOptions.Multiline)] private static partial Regex LeadingWhitespaceRegEx (); - [GeneratedRegex ("\\s+$", RegexOptions.Multiline)] private static partial Regex TrailingWhiteSpaceRegEx (); } diff --git a/Tests/UnitTests/Input/EscSeqUtilsTests.cs b/Tests/UnitTests/Input/EscSeqUtilsTests.cs deleted file mode 100644 index 7a1731e1e..000000000 --- a/Tests/UnitTests/Input/EscSeqUtilsTests.cs +++ /dev/null @@ -1,1582 +0,0 @@ -using System.Text; -using UnitTests; - -// ReSharper disable HeuristicUnreachableCode - -namespace UnitTests.DriverTests; - -public class EscSeqUtilsTests -{ - private bool _actionStarted; - private MouseFlags _arg1; - private Point _arg2; - private string _c1Control, _code, _terminating; - private ConsoleKeyInfo [] _cki; - private bool _isKeyMouse; - private bool _isResponse; - private ConsoleKey _key; - private ConsoleModifiers _mod; - private List _mouseFlags; - private ConsoleKeyInfo _newConsoleKeyInfo; - private Point _pos; - private string [] _values; - - [Fact] - [AutoInitShutdown] - public void DecodeEscSeq_Multiple_Tests () - { - // ESC - _cki = new ConsoleKeyInfo [] { new ('\u001b', 0, false, false, false) }; - var expectedCki = new ConsoleKeyInfo ('\u001b', ConsoleKey.Escape, false, false, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.Escape, _key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("ESC", _c1Control); - Assert.Null (_code); - Assert.Null (_values); - Assert.Null (_terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - _cki = new ConsoleKeyInfo [] { new ('\u001b', 0, false, false, false), new ('\u0012', 0, false, false, false) }; - expectedCki = new ('\u0012', ConsoleKey.R, false, true, true); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.R, _key); - Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod); - Assert.Equal ("ESC", _c1Control); - Assert.Null (_code); - Assert.Null (_values); - Assert.Equal ("\u0012", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - _cki = new ConsoleKeyInfo [] { new ('\u001b', 0, false, false, false), new ('r', 0, false, false, false) }; - expectedCki = new ('r', ConsoleKey.R, false, true, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.R, _key); - Assert.Equal (ConsoleModifiers.Alt, _mod); - Assert.Equal ("ESC", _c1Control); - Assert.Null (_code); - Assert.Null (_values); - Assert.Equal ("r", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - // SS3 - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), new ('O', 0, false, false, false), new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, false, false, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("SS3", _c1Control); - Assert.Null (_code); - Assert.Single (_values); - Assert.Null (_values [0]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - // CSI - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, true, false, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Shift, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("2", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, false, true, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Alt, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('4', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, true, true, false); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("4", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('5', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, false, false, true); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Control, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("5", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('6', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, true, false, true); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Control, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("6", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('7', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, false, true, true); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("7", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('1', 0, false, false, false), - new (';', 0, false, false, false), - new ('8', 0, false, false, false), - new ('R', 0, false, false, false) - }; - expectedCki = new ('\0', ConsoleKey.F3, true, true, true); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.F3, _key); - Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("1", _values [0]); - Assert.Equal ("8", _values [^1]); - Assert.Equal ("R", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("M", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (new () { MouseFlags.Button1Pressed }, _mouseFlags); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('m', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("m", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (2, _mouseFlags.Count); - - Assert.Equal ( - new () { MouseFlags.Button1Released, MouseFlags.Button1Clicked }, - _mouseFlags - ); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("M", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (new () { MouseFlags.Button1DoubleClicked }, _mouseFlags); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("M", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (new () { MouseFlags.Button1TripleClicked }, _mouseFlags); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("M", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (new () { MouseFlags.Button1Pressed }, _mouseFlags); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - - Assert.Equal (MouseFlags.None, _arg1); - Assert.Equal (new (0, 0), _arg2); - - ClearAll (); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('m', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Equal ("<", _code); - Assert.Equal (3, _values.Length); - Assert.Equal ("0", _values [0]); - Assert.Equal ("2", _values [1]); - Assert.Equal ("3", _values [^1]); - Assert.Equal ("m", _terminating); - Assert.True (_isKeyMouse); - Assert.Equal (new () { MouseFlags.Button1Released }, _mouseFlags); - Assert.Equal (new (1, 2), _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - - Assert.Empty (EscSeqRequests.Statuses); - EscSeqRequests.Clear (); - EscSeqRequests.Add ("t"); - - _cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('8', 0, false, false, false), - new (';', 0, false, false, false), - new ('1', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new ('0', 0, false, false, false), - new ('t', 0, false, false, false) - }; - expectedCki = default (ConsoleKeyInfo); - Assert.Single (EscSeqRequests.Statuses); - Assert.Equal ("t", EscSeqRequests.Statuses.ToArray () [^1].Terminator); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (0, (int)_key); - Assert.Equal (0, (int)_mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (3, _values.Length); - Assert.Equal ("8", _values [0]); - Assert.Equal ("10", _values [1]); - Assert.Equal ("20", _values [^1]); - Assert.Equal ("t", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.True (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - } - - [Theory] - [InlineData ('A', ConsoleKey.A, true, true, false, "ESC", '\u001b', 'A')] - [InlineData ('a', ConsoleKey.A, false, true, false, "ESC", '\u001b', 'a')] - [InlineData ('\0', ConsoleKey.Spacebar, false, true, true, "ESC", '\u001b', '\0')] - [InlineData (' ', ConsoleKey.Spacebar, true, true, false, "ESC", '\u001b', ' ')] - [InlineData ('\n', ConsoleKey.Enter, false, true, true, "ESC", '\u001b', '\n')] - [InlineData ('\r', ConsoleKey.Enter, true, true, false, "ESC", '\u001b', '\r')] - public void DecodeEscSeq_More_Multiple_Tests ( - char keyChar, - ConsoleKey consoleKey, - bool shift, - bool alt, - bool control, - string c1Control, - params char [] kChars - ) - { - _cki = new ConsoleKeyInfo [kChars.Length]; - - for (var i = 0; i < kChars.Length; i++) - { - char kChar = kChars [i]; - _cki [i] = new (kChar, 0, false, false, false); - } - - var expectedCki = new ConsoleKeyInfo (keyChar, consoleKey, shift, alt, control); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (consoleKey, _key); - - ConsoleModifiers mods = new (); - - if (shift) - { - mods = ConsoleModifiers.Shift; - } - - if (alt) - { - mods |= ConsoleModifiers.Alt; - } - - if (control) - { - mods |= ConsoleModifiers.Control; - } - - Assert.Equal (mods, _mod); - Assert.Equal (c1Control, _c1Control); - Assert.Null (_code); - Assert.Null (_values); - Assert.Equal (keyChar.ToString (), _terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - } - - [Fact] - public void DecodeEscSeq_IncompleteCKInfos () - { - // This is simulated response from a CSI_ReportTerminalSizeInChars - _cki = - [ - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('8', 0, false, false, false), - new (';', 0, false, false, false), - new ('1', 0, false, false, false), - ]; - - ConsoleKeyInfo expectedCki = default; - - Assert.Null (EscSeqUtils.IncompleteCkInfos); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.None, _key); - Assert.Equal (ConsoleModifiers.None, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal ([0], _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - Assert.NotNull (EscSeqUtils.IncompleteCkInfos); - Assert.Equal (_cki, EscSeqUtils.IncompleteCkInfos); - Assert.Contains (EscSeqUtils.ToString (EscSeqUtils.IncompleteCkInfos), EscSeqUtils.ToString (_cki)); - - _cki = EscSeqUtils.InsertArray ( - EscSeqUtils.IncompleteCkInfos, - [ - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new ('0', 0, false, false, false), - new ('t', 0, false, false, false) - ]); - - expectedCki = default; - - // Add a request to avoid assert failure in the DecodeEscSeq method - EscSeqRequests.Add ("t"); - Assert.Single (EscSeqRequests.Statuses); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (ConsoleKey.None, _key); - - Assert.Equal (ConsoleModifiers.None, _mod); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (3, _values.Length); - Assert.Equal ("t", _terminating); - Assert.False (_isKeyMouse); - Assert.Equal ([0], _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (EscSeqRequests.HasResponse ("t")); - Assert.True (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - Assert.Null (EscSeqUtils.IncompleteCkInfos); - Assert.NotEqual (_cki, EscSeqUtils.IncompleteCkInfos); - - ClearAll (); - } - - [Theory] - [InlineData ('\u001B', ConsoleKey.Escape, false, false, false)] - [InlineData ('\r', ConsoleKey.Enter, false, false, false)] - [InlineData ('1', ConsoleKey.D1, false, false, false)] - [InlineData ('!', ConsoleKey.None, false, false, false)] - [InlineData ('a', ConsoleKey.A, false, false, false)] - [InlineData ('A', ConsoleKey.A, true, false, false)] - [InlineData ('\u0001', ConsoleKey.A, false, false, true)] - [InlineData ('\0', ConsoleKey.Spacebar, false, false, true)] - [InlineData ('\n', ConsoleKey.Enter, false, false, true)] - [InlineData ('\t', ConsoleKey.Tab, false, false, false)] - public void DecodeEscSeq_Single_Tests (char keyChar, ConsoleKey consoleKey, bool shift, bool alt, bool control) - { - _cki = [new (keyChar, 0, false, false, false)]; - var expectedCki = new ConsoleKeyInfo (keyChar, consoleKey, shift, alt, control); - - EscSeqUtils.DecodeEscSeq ( - ref _newConsoleKeyInfo, - ref _key, - _cki, - ref _mod, - out _c1Control, - out _code, - out _values, - out _terminating, - out _isKeyMouse, - out _mouseFlags, - out _pos, - out _isResponse, - ProcessContinuousButtonPressed - ); - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (expectedCki, _newConsoleKeyInfo); - Assert.Equal (consoleKey, _key); - - ConsoleModifiers mods = new (); - - if (shift) - { - mods = ConsoleModifiers.Shift; - } - - if (alt) - { - mods |= ConsoleModifiers.Alt; - } - - if (control) - { - mods |= ConsoleModifiers.Control; - } - - Assert.Equal (mods, _mod); - - if (keyChar == '\u001B') - { - Assert.Equal ("ESC", _c1Control); - } - else - { - Assert.Null (_c1Control); - } - - Assert.Null (_code); - Assert.Null (_values); - Assert.Null (_terminating); - Assert.False (_isKeyMouse); - Assert.Equal (new () { 0 }, _mouseFlags); - Assert.Equal (Point.Empty, _pos); - Assert.False (_isResponse); - Assert.Equal (0, (int)_arg1); - Assert.Equal (Point.Empty, _arg2); - - ClearAll (); - } - - [Fact] - public void Defaults_Values () - { - Assert.Equal ('\x1b', EscSeqUtils.KeyEsc); - Assert.Equal ("\x1b[", EscSeqUtils.CSI); - Assert.Equal ("\x1b[?1003h", EscSeqUtils.CSI_EnableAnyEventMouse); - Assert.Equal ("\x1b[?1006h", EscSeqUtils.CSI_EnableSgrExtModeMouse); - Assert.Equal ("\x1b[?1015h", EscSeqUtils.CSI_EnableUrxvtExtModeMouse); - Assert.Equal ("\x1b[?1003l", EscSeqUtils.CSI_DisableAnyEventMouse); - Assert.Equal ("\x1b[?1006l", EscSeqUtils.CSI_DisableSgrExtModeMouse); - Assert.Equal ("\x1b[?1015l", EscSeqUtils.CSI_DisableUrxvtExtModeMouse); - Assert.Equal ("\x1b[?1003h\x1b[?1015h\u001b[?1006h", EscSeqUtils.CSI_EnableMouseEvents); - Assert.Equal ("\x1b[?1003l\x1b[?1015l\u001b[?1006l", EscSeqUtils.CSI_DisableMouseEvents); - } - - [Fact] - public void GetC1ControlChar_Tests () - { - Assert.Equal ("IND", EscSeqUtils.GetC1ControlChar ('D')); - Assert.Equal ("NEL", EscSeqUtils.GetC1ControlChar ('E')); - Assert.Equal ("HTS", EscSeqUtils.GetC1ControlChar ('H')); - Assert.Equal ("RI", EscSeqUtils.GetC1ControlChar ('M')); - Assert.Equal ("SS2", EscSeqUtils.GetC1ControlChar ('N')); - Assert.Equal ("SS3", EscSeqUtils.GetC1ControlChar ('O')); - Assert.Equal ("DCS", EscSeqUtils.GetC1ControlChar ('P')); - Assert.Equal ("SPA", EscSeqUtils.GetC1ControlChar ('V')); - Assert.Equal ("EPA", EscSeqUtils.GetC1ControlChar ('W')); - Assert.Equal ("SOS", EscSeqUtils.GetC1ControlChar ('X')); - Assert.Equal ("DECID", EscSeqUtils.GetC1ControlChar ('Z')); - Assert.Equal ("CSI", EscSeqUtils.GetC1ControlChar ('[')); - Assert.Equal ("ST", EscSeqUtils.GetC1ControlChar ('\\')); - Assert.Equal ("OSC", EscSeqUtils.GetC1ControlChar (']')); - Assert.Equal ("PM", EscSeqUtils.GetC1ControlChar ('^')); - Assert.Equal ("APC", EscSeqUtils.GetC1ControlChar ('_')); - Assert.Equal ("", EscSeqUtils.GetC1ControlChar ('\0')); - } - - [Fact] - public void GetConsoleInputKey_ConsoleKeyInfo () - { - var cki = new ConsoleKeyInfo ('r', 0, false, false, false); - var expectedCki = new ConsoleKeyInfo ('r', ConsoleKey.R, false, false, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, true, false, false); - expectedCki = new ('r', ConsoleKey.R, true, false, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, false, true, false); - expectedCki = new ('r', ConsoleKey.R, false, true, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, false, false, true); - expectedCki = new ('r', ConsoleKey.R, false, false, true); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, true, true, false); - expectedCki = new ('r', ConsoleKey.R, true, true, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, false, true, true); - expectedCki = new ('r', ConsoleKey.R, false, true, true); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('r', 0, true, true, true); - expectedCki = new ('r', ConsoleKey.R, true, true, true); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('\u0012', 0, false, false, false); - expectedCki = new ('\u0012', ConsoleKey.R, false, false, true); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('\0', (ConsoleKey)64, false, false, true); - expectedCki = new ('\0', ConsoleKey.Spacebar, false, false, true); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('\r', 0, false, false, false); - expectedCki = new ('\r', ConsoleKey.Enter, false, false, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('\u007f', 0, false, false, false); - expectedCki = new ('\u007f', ConsoleKey.Backspace, false, false, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - - cki = new ('R', 0, false, false, false); - expectedCki = new ('R', ConsoleKey.R, true, false, false); - Assert.Equal (expectedCki, EscSeqUtils.MapConsoleKeyInfo (cki)); - } - - [Fact] - public void GetConsoleKey_Tests () - { - ConsoleModifiers mod = 0; - char keyChar = '\0'; - Assert.Equal (ConsoleKey.UpArrow, EscSeqUtils.GetConsoleKey ('A', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.DownArrow, EscSeqUtils.GetConsoleKey ('B', "", ref mod, ref keyChar)); - Assert.Equal (_key = ConsoleKey.RightArrow, EscSeqUtils.GetConsoleKey ('C', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.LeftArrow, EscSeqUtils.GetConsoleKey ('D', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.End, EscSeqUtils.GetConsoleKey ('F', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Home, EscSeqUtils.GetConsoleKey ('H', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F1, EscSeqUtils.GetConsoleKey ('P', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F2, EscSeqUtils.GetConsoleKey ('Q', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F3, EscSeqUtils.GetConsoleKey ('R', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F4, EscSeqUtils.GetConsoleKey ('S', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Tab, EscSeqUtils.GetConsoleKey ('Z', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleModifiers.Shift, mod); - Assert.Equal (0, (int)EscSeqUtils.GetConsoleKey ('\0', "", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Insert, EscSeqUtils.GetConsoleKey ('~', "2", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Delete, EscSeqUtils.GetConsoleKey ('~', "3", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.PageUp, EscSeqUtils.GetConsoleKey ('~', "5", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.PageDown, EscSeqUtils.GetConsoleKey ('~', "6", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F5, EscSeqUtils.GetConsoleKey ('~', "15", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F6, EscSeqUtils.GetConsoleKey ('~', "17", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F7, EscSeqUtils.GetConsoleKey ('~', "18", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F8, EscSeqUtils.GetConsoleKey ('~', "19", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F9, EscSeqUtils.GetConsoleKey ('~', "20", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F10, EscSeqUtils.GetConsoleKey ('~', "21", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F11, EscSeqUtils.GetConsoleKey ('~', "23", ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.F12, EscSeqUtils.GetConsoleKey ('~', "24", ref mod, ref keyChar)); - Assert.Equal (0, (int)EscSeqUtils.GetConsoleKey ('~', "", ref mod, ref keyChar)); - // These terminators are used by macOS on a numeric keypad without keys modifiers - Assert.Equal (ConsoleKey.Add, EscSeqUtils.GetConsoleKey ('l', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Subtract, EscSeqUtils.GetConsoleKey ('m', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Insert, EscSeqUtils.GetConsoleKey ('p', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.End, EscSeqUtils.GetConsoleKey ('q', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.DownArrow, EscSeqUtils.GetConsoleKey ('r', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.PageDown, EscSeqUtils.GetConsoleKey ('s', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.LeftArrow, EscSeqUtils.GetConsoleKey ('t', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Clear, EscSeqUtils.GetConsoleKey ('u', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.RightArrow, EscSeqUtils.GetConsoleKey ('v', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.Home, EscSeqUtils.GetConsoleKey ('w', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.UpArrow, EscSeqUtils.GetConsoleKey ('x', null, ref mod, ref keyChar)); - Assert.Equal (ConsoleKey.PageUp, EscSeqUtils.GetConsoleKey ('y', null, ref mod, ref keyChar)); - } - - [Fact] - public void GetConsoleModifiers_Tests () - { - Assert.Equal (ConsoleModifiers.Shift, EscSeqUtils.GetConsoleModifiers ("2")); - Assert.Equal (ConsoleModifiers.Alt, EscSeqUtils.GetConsoleModifiers ("3")); - Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt, EscSeqUtils.GetConsoleModifiers ("4")); - Assert.Equal (ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("5")); - Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("6")); - Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("7")); - - Assert.Equal ( - ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, - EscSeqUtils.GetConsoleModifiers ("8") - ); - Assert.Equal (0, (int)EscSeqUtils.GetConsoleModifiers ("")); - } - - [Fact] - public void GetEscapeResult_Multiple_Tests () - { - char [] kChars = ['\u001b', '[', '5', ';', '1', '0', 'r']; - (_c1Control, _code, _values, _terminating) = EscSeqUtils.GetEscapeResult (kChars); - Assert.Equal ("CSI", _c1Control); - Assert.Null (_code); - Assert.Equal (2, _values.Length); - Assert.Equal ("5", _values [0]); - Assert.Equal ("10", _values [^1]); - Assert.Equal ("r", _terminating); - - ClearAll (); - } - - [Theory] - [InlineData ('\u001B')] - [InlineData (['\r'])] - [InlineData (['1'])] - [InlineData (['!'])] - [InlineData (['a'])] - [InlineData (['A'])] - public void GetEscapeResult_Single_Tests (params char [] kChars) - { - (_c1Control, _code, _values, _terminating) = EscSeqUtils.GetEscapeResult (kChars); - - if (kChars [0] == '\u001B') - { - Assert.Equal ("ESC", _c1Control); - } - else - { - Assert.Null (_c1Control); - } - - Assert.Null (_code); - Assert.Null (_values); - Assert.Null (_terminating); - - ClearAll (); - } - - [Fact] - public void GetKeyCharArray_Tests () - { - ConsoleKeyInfo [] cki = - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('5', 0, false, false, false), - new (';', 0, false, false, false), - new ('1', 0, false, false, false), - new ('0', 0, false, false, false), - new ('r', 0, false, false, false) - }; - - Assert.Equal (new [] { '\u001b', '[', '5', ';', '1', '0', 'r' }, EscSeqUtils.GetKeyCharArray (cki)); - } - - [Fact] - [AutoInitShutdown] - public void GetMouse_Tests () - { - ConsoleKeyInfo [] cki = - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - EscSeqUtils.GetMouse (cki, out List mouseFlags, out Point pos, ProcessContinuousButtonPressed); - Assert.Equal (new () { MouseFlags.Button1Pressed }, mouseFlags); - Assert.Equal (new (1, 2), pos); - - cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('m', 0, false, false, false) - }; - EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed); - Assert.Equal (2, mouseFlags.Count); - - Assert.Equal ( - new () { MouseFlags.Button1Released, MouseFlags.Button1Clicked }, - mouseFlags - ); - Assert.Equal (new (1, 2), pos); - - cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed); - Assert.Equal (new () { MouseFlags.Button1DoubleClicked }, mouseFlags); - Assert.Equal (new (1, 2), pos); - - cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('M', 0, false, false, false) - }; - EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed); - Assert.Equal (new () { MouseFlags.Button1TripleClicked }, mouseFlags); - Assert.Equal (new (1, 2), pos); - - cki = new ConsoleKeyInfo [] - { - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('<', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new (';', 0, false, false, false), - new ('3', 0, false, false, false), - new ('m', 0, false, false, false) - }; - EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed); - Assert.Equal (new () { MouseFlags.Button1Released }, mouseFlags); - Assert.Equal (new (1, 2), pos); - } - - [Fact] - public void ResizeArray_ConsoleKeyInfo () - { - ConsoleKeyInfo [] expectedCkInfos = null; - var cki = new ConsoleKeyInfo ('\u001b', ConsoleKey.Escape, false, false, false); - expectedCkInfos = EscSeqUtils.ResizeArray (cki, expectedCkInfos); - Assert.Single (expectedCkInfos); - Assert.Equal (cki, expectedCkInfos [0]); - } - - [Theory] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\b", "\b")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\t", "\t")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\n", "\n")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\r", "\r")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOCe", "e")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOCV", "V")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\u007f", "\u007f")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC ", " ")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\\", "\\")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC|", "|")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC1", "1")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC!", "!")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC\"", "\"")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC@", "@")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC#", "#")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC£", "£")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC$", "$")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC§", "§")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC%", "%")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC€", "€")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC&", "&")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC/", "/")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC{", "{")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC(", "(")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC[", "[")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC)", ")")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC]", "]")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC=", "=")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC}", "}")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC'", "'")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC?", "?")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC«", "«")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC»", "»")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC+", "+")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC*", "*")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC¨", "¨")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC´", "´")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC`", "`")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOCç", "ç")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOCº", "º")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOCª", "ª")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC~", "~")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC^", "^")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC<", "<")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC>", ">")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC,", ",")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC;", ";")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC.", ".")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC:", ":")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC-", "-")] - [InlineData ("\r[<35;50;1m[<35;49;1m[<35;47;1m[<35;46;1m[<35;45;2m[<35;44;2m[<35;43;3m[<35;42;3m[<35;41;4m[<35;40;5m[<35;39;6m[<35;49;1m[<35;48;2m[<0;33;6M[<0;33;6mOC_", "_")] - public void SplitEscapeRawString_Multiple_Tests (string rawData, string expectedLast) - { - List splitList = EscSeqUtils.SplitEscapeRawString (rawData); - Assert.Equal (18, splitList.Count); - Assert.Equal ("\r", splitList [0]); - Assert.Equal ("\u001b[<35;50;1m", splitList [1]); - Assert.Equal ("\u001b[<35;49;1m", splitList [2]); - Assert.Equal ("\u001b[<35;47;1m", splitList [3]); - Assert.Equal ("\u001b[<35;46;1m", splitList [4]); - Assert.Equal ("\u001b[<35;45;2m", splitList [5]); - Assert.Equal ("\u001b[<35;44;2m", splitList [6]); - Assert.Equal ("\u001b[<35;43;3m", splitList [7]); - Assert.Equal ("\u001b[<35;42;3m", splitList [8]); - Assert.Equal ("\u001b[<35;41;4m", splitList [9]); - Assert.Equal ("\u001b[<35;40;5m", splitList [10]); - Assert.Equal ("\u001b[<35;39;6m", splitList [11]); - Assert.Equal ("\u001b[<35;49;1m", splitList [12]); - Assert.Equal ("\u001b[<35;48;2m", splitList [13]); - Assert.Equal ("\u001b[<0;33;6M", splitList [14]); - Assert.Equal ("\u001b[<0;33;6m", splitList [15]); - Assert.Equal ("\u001bOC", splitList [16]); - Assert.Equal (expectedLast, splitList [^1]); - } - - [Theory] - [InlineData ("[<35;50;1m")] - [InlineData ("\r")] - [InlineData ("1")] - [InlineData ("!")] - [InlineData ("a")] - [InlineData ("A")] - public void SplitEscapeRawString_Single_Tests (string rawData) - { - List splitList = EscSeqUtils.SplitEscapeRawString (rawData); - Assert.Single (splitList); - Assert.Equal (rawData, splitList [0]); - } - - [Theory] - [InlineData (null, null, null, null)] - [InlineData ("\u001b[8;1", null, null, "\u001b[8;1")] - [InlineData (null, "\u001b[8;1", 5, "\u001b[8;1")] - [InlineData ("\u001b[8;1", null, 5, "\u001b[8;1")] - [InlineData ("\u001b[8;1", "0;20t", -1, "\u001b[8;10;20t")] - [InlineData ("\u001b[8;1", "0;20t", 0, "\u001b[8;10;20t")] - [InlineData ("0;20t", "\u001b[8;1", 5, "\u001b[8;10;20t")] - [InlineData ("0;20t", "\u001b[8;1", 3, "\u001b[80;20t;1")] - public void InsertArray_Tests (string toInsert, string current, int? index, string expected) - { - ConsoleKeyInfo [] toIns = EscSeqUtils.ToConsoleKeyInfoArray (toInsert); - ConsoleKeyInfo [] cki = EscSeqUtils.ToConsoleKeyInfoArray (current); - ConsoleKeyInfo [] result = EscSeqUtils.ToConsoleKeyInfoArray (expected); - - if (index is null) - { - cki = EscSeqUtils.InsertArray (toIns, cki); - } - else - { - cki = EscSeqUtils.InsertArray (toIns, cki, (int)index); - } - - Assert.Equal (result, cki); - } - - [Theory] - [InlineData (0, 0, $"{EscSeqUtils.CSI}0;0H")] - [InlineData (int.MaxValue, int.MaxValue, $"{EscSeqUtils.CSI}2147483647;2147483647H")] - [InlineData (int.MinValue, int.MinValue, $"{EscSeqUtils.CSI}-2147483648;-2147483648H")] - public void CSI_WriteCursorPosition_ReturnsCorrectEscSeq (int row, int col, string expected) - { - StringBuilder builder = new(); - using StringWriter writer = new(builder); - - EscSeqUtils.CSI_WriteCursorPosition (writer, row, col); - - string actual = builder.ToString(); - Assert.Equal (expected, actual); - } - - [Theory] - [InlineData ('\u001B', KeyCode.Esc)] - [InlineData ('\r', KeyCode.Enter)] - [InlineData ('1', KeyCode.D1)] - [InlineData ('!', (KeyCode)'!')] - [InlineData ('a', KeyCode.A)] - [InlineData ('A', KeyCode.A | KeyCode.ShiftMask)] - public void MapChar_Returns_Modifiers_If_Needed (char ch, KeyCode keyCode) - { - ConsoleKeyInfo cki = EscSeqUtils.MapChar (ch); - Key key = EscSeqUtils.MapKey (cki); - Key expectedKey = keyCode; - - Assert.Equal (key, expectedKey); - } - - private void ClearAll () - { - EscSeqRequests.Clear (); - _newConsoleKeyInfo = default (ConsoleKeyInfo); - _key = default (ConsoleKey); - _cki = default (ConsoleKeyInfo []); - _mod = default (ConsoleModifiers); - _c1Control = default (string); - _code = default (string); - _terminating = default (string); - _values = default (string []); - _isKeyMouse = default (bool); - _isResponse = false; - _mouseFlags = default (List); - _pos = default (Point); - _arg1 = default (MouseFlags); - _arg2 = default (Point); - } - - private void ProcessContinuousButtonPressed (MouseFlags arg1, Point arg2) - { - _arg1 = arg1; - _arg2 = arg2; - _actionStarted = true; - } -} diff --git a/Tests/UnitTests/SetupFakeDriverAttribute.cs b/Tests/UnitTests/SetupFakeDriverAttribute.cs index 9d1cadeb4..c63ca267d 100644 --- a/Tests/UnitTests/SetupFakeDriverAttribute.cs +++ b/Tests/UnitTests/SetupFakeDriverAttribute.cs @@ -36,11 +36,10 @@ public class SetupFakeDriverAttribute : BeforeAfterTestAttribute Application.ResetState (true); Assert.Null (Application.Driver); - var ff = new FakeDriverFactory (); - var driver = ff.Create (); + var driver = new FakeDriver (); Application.Driver = driver; - driver.SetBufferSize (25, 25); + driver.SetScreenSize (25, 25); Assert.Equal (new (0, 0, 25, 25), Application.Screen); // Ensures subscribing events, at least for the SizeChanged event diff --git a/Tests/UnitTests/TestsAllViews.cs b/Tests/UnitTests/TestsAllViews.cs index 056a5050c..02bbc1c2f 100644 --- a/Tests/UnitTests/TestsAllViews.cs +++ b/Tests/UnitTests/TestsAllViews.cs @@ -1,6 +1,6 @@ #nullable enable -using System.Drawing; using System.Reflection; +using System.Drawing; namespace UnitTests; @@ -15,13 +15,12 @@ public class TestsAllViews public static IEnumerable AllViewTypes => typeof (View).Assembly .GetTypes () - .Where ( - type => type is { IsClass: true, IsAbstract: false, IsPublic: true } + .Where (type => type is { IsClass: true, IsAbstract: false, IsPublic: true } && (type.IsSubclassOf (typeof (View)) || type == typeof (View))) .Select (type => new object [] { type }); /// - /// Creates an instance of a view if it is not a generic type. + /// Creates an instance of a view if it is not a generic type. /// /// /// @@ -43,8 +42,7 @@ public class TestsAllViews public static List GetAllViewClasses () { return typeof (View).Assembly.GetTypes () - .Where ( - myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true } + .Where (myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true } && myType.IsSubclassOf (typeof (View)) ) .ToList (); @@ -83,6 +81,7 @@ public class TestsAllViews if (type.ContainsGenericParameters) { Logging.Warning ($"Cannot create an instance of {type} because it contains generic parameters."); + //throw new ArgumentException ($"Cannot create an instance of {type} because it contains generic parameters."); return null; } diff --git a/Tests/UnitTests/Text/AutocompleteTests.cs b/Tests/UnitTests/Text/AutocompleteTests.cs index deaf1d38f..eceb5cd33 100644 --- a/Tests/UnitTests/Text/AutocompleteTests.cs +++ b/Tests/UnitTests/Text/AutocompleteTests.cs @@ -1,5 +1,4 @@ using System.Text.RegularExpressions; -using UnitTests; using Xunit.Abstractions; namespace UnitTests.TextTests; @@ -10,7 +9,8 @@ public class AutocompleteTests (ITestOutputHelper output) [AutoInitShutdown] public void CursorLeft_CursorRight_Mouse_Button_Pressed_Does_Not_Show_Popup () { - AutoInitShutdownAttribute.FakeResize (new Size (50,5)); + Application.Driver?.SetScreenSize (50, 5); + var tv = new TextView { Width = 50, Height = 5, Text = "This a long line and against TextView." }; var g = (SingleWordSuggestionGenerator)tv.Autocomplete.SuggestionGenerator; @@ -279,6 +279,4 @@ This an long line and against TextView.", Assert.Equal (new (Color.Black), tv.Autocomplete.Scheme.Focus.Foreground); Assert.Equal (new (Color.Cyan), tv.Autocomplete.Scheme.Focus.Background); } - - } diff --git a/Tests/UnitTests/Text/TextFormatterTests.cs b/Tests/UnitTests/Text/TextFormatterTests.cs index 1f1e7819c..b4385ec60 100644 --- a/Tests/UnitTests/Text/TextFormatterTests.cs +++ b/Tests/UnitTests/Text/TextFormatterTests.cs @@ -3828,7 +3828,7 @@ ssb [SetupFakeDriver] public void FillRemaining_True_False () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (22, 5); + Application.Driver!.SetScreenSize (22, 5); Attribute [] attrs = { @@ -4050,7 +4050,7 @@ Nice Work")] Size tfSize = tf.FormatAndGetSize (); Assert.Equal (new (59, 13), tfSize); - ((IFakeConsoleDriver)Application.Driver).SetBufferSize (tfSize.Width, tfSize.Height); + Application.Driver!.SetScreenSize (tfSize.Width, tfSize.Height); Application.Driver.FillRect (Application.Screen, (Rune)'*'); tf.Draw (Application.Screen, Attribute.Default, Attribute.Default); diff --git a/Tests/UnitTests/View/Adornment/AdornmentSubViewTests.cs b/Tests/UnitTests/View/Adornment/AdornmentSubViewTests.cs index d1ac1cebe..52d5bc01e 100644 --- a/Tests/UnitTests/View/Adornment/AdornmentSubViewTests.cs +++ b/Tests/UnitTests/View/Adornment/AdornmentSubViewTests.cs @@ -19,9 +19,9 @@ public class AdornmentSubViewTests (ITestOutputHelper output) Width = 10, Height = 10 }; - Application.Top.Margin.Thickness = new Thickness (viewMargin); + Application.Top.Margin!.Thickness = new Thickness (viewMargin); // Turn of TransparentMouse for the test - Application.Top.Margin.ViewportSettings = ViewportSettingsFlags.None; + Application.Top.Margin!.ViewportSettings = ViewportSettingsFlags.None; var subView = new View () { @@ -30,11 +30,11 @@ public class AdornmentSubViewTests (ITestOutputHelper output) Width = 5, Height = 5 }; - subView.Margin.Thickness = new Thickness (subViewMargin); + subView.Margin!.Thickness = new Thickness (subViewMargin); // Turn of TransparentMouse for the test - subView.Margin.ViewportSettings = ViewportSettingsFlags.None; + subView.Margin!.ViewportSettings = ViewportSettingsFlags.None; - Application.Top.Margin.Add (subView); + Application.Top.Margin!.Add (subView); Application.Top.Layout (); var foundView = View.GetViewsUnderLocation (new Point(0, 0), ViewportSettingsFlags.None).LastOrDefault (); diff --git a/Tests/UnitTests/View/Adornment/BorderTests.cs b/Tests/UnitTests/View/Adornment/BorderTests.cs index 3ada74ef6..65820dcfe 100644 --- a/Tests/UnitTests/View/Adornment/BorderTests.cs +++ b/Tests/UnitTests/View/Adornment/BorderTests.cs @@ -1,5 +1,4 @@ -using UnitTests; -using Xunit.Abstractions; +using Xunit.Abstractions; namespace UnitTests.ViewTests; @@ -17,17 +16,18 @@ public class BorderTests (ITestOutputHelper output) superView.Add (view); view.Border!.Thickness = new (0, 1, 0, 0); - view.Border.LineStyle = LineStyle.Single; + view.Border!.LineStyle = LineStyle.Single; - view.SetScheme (new () - { - Normal = new (Color.Red, Color.Green), - Focus = new (Color.Green, Color.Red) - }); + view.SetScheme ( + new () + { + Normal = new (Color.Red, Color.Green), + Focus = new (Color.Green, Color.Red) + }); Assert.NotEqual (view.GetScheme ().Normal.Foreground, view.GetScheme ().Focus.Foreground); - Assert.Equal (ColorName16.Red, view.Border.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ()); - Assert.Equal (ColorName16.Green, view.Border.GetAttributeForRole (VisualRole.Focus).Foreground.GetClosestNamedColor16 ()); - Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border.GetAttributeForRole (VisualRole.Focus)); + Assert.Equal (ColorName16.Red, view.Border!.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ()); + Assert.Equal (ColorName16.Green, view.Border!.GetAttributeForRole (VisualRole.Focus).Foreground.GetClosestNamedColor16 ()); + Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border!.GetAttributeForRole (VisualRole.Focus)); superView.BeginInit (); superView.EndInit (); @@ -41,9 +41,9 @@ public class BorderTests (ITestOutputHelper output) view.SetFocus (); View.SetClipToScreen (); view.Draw (); - Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border.GetAttributeForRole (VisualRole.Focus)); - Assert.Equal (view.GetScheme ().Focus.Foreground, view.Border.GetAttributeForRole (VisualRole.Focus).Foreground); - Assert.Equal (view.GetScheme ().Normal.Foreground, view.Border.GetAttributeForRole (VisualRole.Normal).Foreground); + Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border!.GetAttributeForRole (VisualRole.Focus)); + Assert.Equal (view.GetScheme ().Focus.Foreground, view.Border!.GetAttributeForRole (VisualRole.Focus).Foreground); + Assert.Equal (view.GetScheme ().Normal.Foreground, view.Border!.GetAttributeForRole (VisualRole.Normal).Foreground); DriverAssert.AssertDriverAttributesAre ("00100", output, null, view.GetScheme ().Normal, view.GetAttributeForRole (VisualRole.Focus)); } @@ -52,17 +52,18 @@ public class BorderTests (ITestOutputHelper output) public void Border_Uses_Parent_Scheme () { var view = new View { Title = "A", Height = 2, Width = 5 }; - view.Border.Thickness = new (0, 1, 0, 0); - view.Border.LineStyle = LineStyle.Single; + view.Border!.Thickness = new (0, 1, 0, 0); + view.Border!.LineStyle = LineStyle.Single; - view.SetScheme (new () - { - Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red) - }); - Assert.Equal (ColorName16.Red, view.Border.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ()); - Assert.Equal (ColorName16.Green, view.Border.GetAttributeForRole (VisualRole.Focus).Foreground.GetClosestNamedColor16 ()); - Assert.Equal (view.GetAttributeForRole (VisualRole.Normal), view.Border.GetAttributeForRole (VisualRole.Normal)); - Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border.GetAttributeForRole (VisualRole.Focus)); + view.SetScheme ( + new () + { + Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red) + }); + Assert.Equal (ColorName16.Red, view.Border!.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ()); + Assert.Equal (ColorName16.Green, view.Border!.GetAttributeForRole (VisualRole.Focus).Foreground.GetClosestNamedColor16 ()); + Assert.Equal (view.GetAttributeForRole (VisualRole.Normal), view.Border!.GetAttributeForRole (VisualRole.Normal)); + Assert.Equal (view.GetAttributeForRole (VisualRole.Focus), view.Border!.GetAttributeForRole (VisualRole.Focus)); view.BeginInit (); view.EndInit (); @@ -92,12 +93,11 @@ public class BorderTests (ITestOutputHelper output) { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness = win.Border.Thickness with { Top = 4 }; + win.Border!.Thickness = win.Border!.Thickness with { Top = 4 }; RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(width, 5)); + Application.Driver!.SetScreenSize (width, 5); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -226,11 +226,11 @@ public class BorderTests (ITestOutputHelper output) { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness = win.Border.Thickness with { Top = 3 }; + win.Border!.Thickness = win.Border!.Thickness with { Top = 3 }; RunState rs = Application.Begin (win); - AutoInitShutdownAttribute.FakeResize(new Size(width, 4)); + Application.Driver!.SetScreenSize (width, 4); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -359,12 +359,11 @@ public class BorderTests (ITestOutputHelper output) { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double }; - win.Border.Thickness = win.Border.Thickness with { Top = 2 }; + win.Border!.Thickness = win.Border!.Thickness with { Top = 2 }; RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(width, 4)); + Application.Driver!.SetScreenSize (width, 4); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -485,9 +484,8 @@ public class BorderTests (ITestOutputHelper output) var win = new Window { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill () }; RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(20, height)); + Application.Driver!.SetScreenSize (20, height); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -547,9 +545,8 @@ public class BorderTests (ITestOutputHelper output) var win = new Window { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill () }; RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(width, 3)); + Application.Driver!.SetScreenSize (width, 3); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -727,13 +724,12 @@ public class BorderTests (ITestOutputHelper output) var top = new Toplevel (); top.BorderStyle = LineStyle.Double; - var frame = new FrameView { Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single}; + var frame = new FrameView { Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single }; top.Add (frame); RunState rs = Application.Begin (top); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(5, 5)); + Application.Driver!.SetScreenSize (5, 5); AutoInitShutdownAttribute.RunIteration (); var expected = @" @@ -759,9 +755,8 @@ public class BorderTests (ITestOutputHelper output) top.Add (frame); RunState rs = Application.Begin (top); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(10, 4)); + Application.Driver!.SetScreenSize (10, 4); AutoInitShutdownAttribute.RunIteration (); var expected = @" @@ -782,9 +777,8 @@ public class BorderTests (ITestOutputHelper output) var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () }; RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(3, 3)); + Application.Driver!.SetScreenSize (3, 3); AutoInitShutdownAttribute.RunIteration (); var expected = @" @@ -801,7 +795,7 @@ public class BorderTests (ITestOutputHelper output) { var view = new View (); Assert.Equal (LineStyle.None, view.BorderStyle); - Assert.Equal (Thickness.Empty, view.Border.Thickness); + Assert.Equal (Thickness.Empty, view.Border!.Thickness); view.Dispose (); } @@ -811,26 +805,30 @@ public class BorderTests (ITestOutputHelper output) var view = new View (); view.BorderStyle = LineStyle.Single; Assert.Equal (LineStyle.Single, view.BorderStyle); - Assert.Equal (new (1), view.Border.Thickness); + Assert.Equal (new (1), view.Border!.Thickness); view.BorderStyle = LineStyle.Double; Assert.Equal (LineStyle.Double, view.BorderStyle); - Assert.Equal (new (1), view.Border.Thickness); + Assert.Equal (new (1), view.Border!.Thickness); view.BorderStyle = LineStyle.None; Assert.Equal (LineStyle.None, view.BorderStyle); - Assert.Equal (Thickness.Empty, view.Border.Thickness); + Assert.Equal (Thickness.Empty, view.Border!.Thickness); view.Dispose (); } [Theory] - [InlineData (false, @" + [InlineData ( + false, + @" ┌───┐ │ ║ │ │═┌┄│ │ ┊ │ └───┘")] - [InlineData (true, @" + [InlineData ( + true, + @" ╔═╦─┐ ║ ║ │ ╠═╬┄┤ @@ -839,7 +837,7 @@ public class BorderTests (ITestOutputHelper output) [SetupFakeDriver] public void SuperViewRendersLineCanvas_No_SubViews_AutoJoinsLines (bool superViewRendersLineCanvas, string expected) { - View superView = new View () + var superView = new View { Id = "superView", Width = 5, @@ -847,7 +845,7 @@ public class BorderTests (ITestOutputHelper output) BorderStyle = LineStyle.Single }; - View view1 = new View () + var view1 = new View { Id = "view1", Width = 3, @@ -858,7 +856,7 @@ public class BorderTests (ITestOutputHelper output) SuperViewRendersLineCanvas = superViewRendersLineCanvas }; - View view2 = new View () + var view2 = new View { Id = "view2", Width = 3, @@ -878,9 +876,10 @@ public class BorderTests (ITestOutputHelper output) DriverAssert.AssertDriverContentsAre (expected, output); } - [Theory] - [InlineData (false, @" + [InlineData ( + false, + @" ┌┤A├──────┐ │ ║ │ │ ║ │ @@ -888,7 +887,9 @@ public class BorderTests (ITestOutputHelper output) │ ┊ │ │ ┊ │ └─────────┘")] - [InlineData (true, @" + [InlineData ( + true, + @" ╔╡A╞═╦────┐ ║ ║ │ ║ ║ │ @@ -899,17 +900,17 @@ public class BorderTests (ITestOutputHelper output) [SetupFakeDriver] public void SuperViewRendersLineCanvas_Title_AutoJoinsLines (bool superViewRendersLineCanvas, string expected) { - View superView = new View () + var superView = new View { Id = "superView", Title = "A", Width = 11, Height = 7, CanFocus = true, - BorderStyle = LineStyle.Single, + BorderStyle = LineStyle.Single }; - View view1 = new View () + var view1 = new View { Id = "view1", Title = "B", @@ -922,7 +923,7 @@ public class BorderTests (ITestOutputHelper output) SuperViewRendersLineCanvas = superViewRendersLineCanvas }; - View view2 = new View () + var view2 = new View { Id = "view2", Title = "C", diff --git a/Tests/UnitTests/View/Adornment/MarginTests.cs b/Tests/UnitTests/View/Adornment/MarginTests.cs index ff678a311..99c1a9159 100644 --- a/Tests/UnitTests/View/Adornment/MarginTests.cs +++ b/Tests/UnitTests/View/Adornment/MarginTests.cs @@ -9,7 +9,7 @@ public class MarginTests (ITestOutputHelper output) [SetupFakeDriver] public void Margin_Is_Transparent () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (5, 5); + Application.Driver!.SetScreenSize (5, 5); var view = new View { Height = 3, Width = 3 }; view.Margin!.Diagnostics = ViewDiagnosticFlags.Thickness; @@ -44,7 +44,7 @@ public class MarginTests (ITestOutputHelper output) [SetupFakeDriver] public void Margin_ViewPortSettings_Not_Transparent_Is_NotTransparent () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (5, 5); + Application.Driver!.SetScreenSize (5, 5); var view = new View { Height = 3, Width = 3 }; view.Margin!.Diagnostics = ViewDiagnosticFlags.Thickness; diff --git a/Tests/UnitTests/View/Adornment/PaddingTests.cs b/Tests/UnitTests/View/Adornment/PaddingTests.cs index d9a9a6141..b82a9e721 100644 --- a/Tests/UnitTests/View/Adornment/PaddingTests.cs +++ b/Tests/UnitTests/View/Adornment/PaddingTests.cs @@ -9,7 +9,7 @@ public class PaddingTests (ITestOutputHelper output) [SetupFakeDriver] public void Padding_Uses_Parent_Scheme () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (5, 5); + Application.Driver!.SetScreenSize (5, 5); var view = new View { Height = 3, Width = 3 }; view.Padding!.Thickness = new (1); view.Padding.Diagnostics = ViewDiagnosticFlags.Thickness; diff --git a/Tests/UnitTests/View/Adornment/ShadowStyleTests.cs b/Tests/UnitTests/View/Adornment/ShadowStyleTests.cs index b8ff317e6..cbd11f0a8 100644 --- a/Tests/UnitTests/View/Adornment/ShadowStyleTests.cs +++ b/Tests/UnitTests/View/Adornment/ShadowStyleTests.cs @@ -30,7 +30,7 @@ public class ShadowStyleTests (ITestOutputHelper output) [SetupFakeDriver] public void ShadowView_Colors (ShadowStyle style, string expectedAttrs) { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (5, 5); + Application.Driver!.SetScreenSize (5, 5); Color fg = Color.Red; Color bg = Color.Green; @@ -100,7 +100,7 @@ public class ShadowStyleTests (ITestOutputHelper output) [SetupFakeDriver] public void Visual_Test (ShadowStyle style, string expected) { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (5, 5); + Application.Driver!.SetScreenSize (5, 5); var superView = new Toplevel { diff --git a/Tests/UnitTests/View/Draw/ClearViewportTests.cs b/Tests/UnitTests/View/Draw/ClearViewportTests.cs index 4341fbdd6..5058f3df4 100644 --- a/Tests/UnitTests/View/Draw/ClearViewportTests.cs +++ b/Tests/UnitTests/View/Draw/ClearViewportTests.cs @@ -209,7 +209,7 @@ public class ClearViewportTests (ITestOutputHelper output) var top = new Toplevel (); top.Add (view); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize (20, 10); var expected = @" ┌──────────────────┐ @@ -274,7 +274,7 @@ public class ClearViewportTests (ITestOutputHelper output) var top = new Toplevel (); top.Add (view); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize (20, 10); var expected = @" ┌──────────────────┐ diff --git a/Tests/UnitTests/View/Draw/ClipTests.cs b/Tests/UnitTests/View/Draw/ClipTests.cs index 05f62a4d0..46397654c 100644 --- a/Tests/UnitTests/View/Draw/ClipTests.cs +++ b/Tests/UnitTests/View/Draw/ClipTests.cs @@ -171,7 +171,7 @@ public class ClipTests (ITestOutputHelper _output) [Trait ("Category", "Unicode")] public void Clipping_Wide_Runes () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (30, 1); + Application.Driver!.SetScreenSize (30, 1); var top = new View { @@ -190,7 +190,7 @@ public class ClipTests (ITestOutputHelper _output) """ }; frameView.Border!.LineStyle = LineStyle.Single; - frameView.Border.Thickness = new (1, 0, 0, 0); + frameView.Border!.Thickness = new (1, 0, 0, 0); top.Add (frameView); View.SetClipToScreen (); diff --git a/Tests/UnitTests/View/Draw/DrawTests.cs b/Tests/UnitTests/View/Draw/DrawTests.cs index 5c1843ce2..6ef42470c 100644 --- a/Tests/UnitTests/View/Draw/DrawTests.cs +++ b/Tests/UnitTests/View/Draw/DrawTests.cs @@ -32,7 +32,7 @@ public class DrawTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(10, 4)) ; + Application.Driver!.SetScreenSize (10, 4); const string expectedOutput = """ @@ -75,7 +75,7 @@ public class DrawTests (ITestOutputHelper output) top.Add (viewRight, viewBottom); var rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(7, 7)); + Application.Driver!.SetScreenSize (7, 7); AutoInitShutdownAttribute.RunIteration (); DriverAssert.AssertDriverContentsWithFrameAre ( @@ -616,7 +616,7 @@ public class DrawTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(10, 4)); + Application.Driver!.SetScreenSize (10, 4); var expected = """ diff --git a/Tests/UnitTests/View/Draw/NeedsDrawTests.cs b/Tests/UnitTests/View/Draw/NeedsDrawTests.cs index 8e2370fd1..7ec2ec4ce 100644 --- a/Tests/UnitTests/View/Draw/NeedsDrawTests.cs +++ b/Tests/UnitTests/View/Draw/NeedsDrawTests.cs @@ -39,7 +39,7 @@ public class NeedsDrawTests () RunState runState = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); + Application.Driver!.SetScreenSize (80,25); top.SubViewsLaidOut += (s, e) => { Assert.Equal (new (0, 0, 80, 25), top.NeedsDrawRect); }; diff --git a/Tests/UnitTests/View/Layout/Dim.Tests.cs b/Tests/UnitTests/View/Layout/Dim.Tests.cs index b15f1175b..efe0bc333 100644 --- a/Tests/UnitTests/View/Layout/Dim.Tests.cs +++ b/Tests/UnitTests/View/Layout/Dim.Tests.cs @@ -127,7 +127,7 @@ public class DimTests Assert.Equal (49, f2.Frame.Width); // 50-1=49 Assert.Equal (5, f2.Frame.Height); - Assert.Equal ($"Combine(View(Width,FrameView(){f1.Border.Frame})-Absolute(2))", v1.Width.ToString ()); + Assert.Equal ($"Combine(View(Width,FrameView(){f1.Border!.Frame})-Absolute(2))", v1.Width.ToString ()); Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v1.Height.ToString ()); Assert.Equal (47, v1.Frame.Width); // 49-2=47 Assert.Equal (89, v1.Frame.Height); // 98-5-2-2=89 diff --git a/Tests/UnitTests/View/Layout/GetViewsUnderLocationTests.cs b/Tests/UnitTests/View/Layout/GetViewsUnderLocationTests.cs index 5fe8e91fd..ec1fcdd08 100644 --- a/Tests/UnitTests/View/Layout/GetViewsUnderLocationTests.cs +++ b/Tests/UnitTests/View/Layout/GetViewsUnderLocationTests.cs @@ -76,9 +76,9 @@ public class GetViewsUnderLocationTests Frame = new (frameX, frameY, 10, 10) }; Application.Top.Margin!.Thickness = new (marginThickness); - Application.Top.Margin.Id = "Margin"; + Application.Top.Margin!.Id = "Margin"; Application.Top.Border!.Thickness = new (borderThickness); - Application.Top.Border.Id = "Border"; + Application.Top.Border!.Id = "Border"; Application.Top.Padding!.Thickness = new (paddingThickness); Application.Top.Padding.Id = "Padding"; @@ -353,9 +353,9 @@ public class GetViewsUnderLocationTests Width = 10, Height = 10 }; Application.Top.Margin!.Thickness = new (1); - Application.Top.Margin.Id = "Margin"; + Application.Top.Margin!.Id = "Margin"; Application.Top.Border!.Thickness = new (1); - Application.Top.Border.Id = "Border"; + Application.Top.Border!.Id = "Border"; Application.Top.Padding!.Thickness = new (1); Application.Top.Padding.Id = "Padding"; @@ -401,7 +401,7 @@ public class GetViewsUnderLocationTests Width = 5, Height = 5 }; subview.Border!.Thickness = new (1); - subview.Border.Id = "border"; + subview.Border!.Id = "border"; Application.Top.Add (subview); List viewsUnderMouse = View.GetViewsUnderLocation (new (testX, testY), ViewportSettingsFlags.TransparentMouse); @@ -438,8 +438,8 @@ public class GetViewsUnderLocationTests Width = 5, Height = 5 }; subview.Border!.Thickness = new (1); - subview.Border.ViewportSettings = ViewportSettingsFlags.TransparentMouse; - subview.Border.Id = "border"; + subview.Border!.ViewportSettings = ViewportSettingsFlags.TransparentMouse; + subview.Border!.Id = "border"; Application.Top.Add (subview); List viewsUnderMouse = View.GetViewsUnderLocation (new (testX, testY), ViewportSettingsFlags.TransparentMouse); @@ -786,14 +786,14 @@ public class GetViewsUnderLocationTests Application.TopLevels.Push (secondaryToplevel); Application.Top = secondaryToplevel; - secondaryToplevel.Margin.ViewportSettings = ViewportSettingsFlags.None; + secondaryToplevel.Margin!.ViewportSettings = ViewportSettingsFlags.None; List found = View.GetViewsUnderLocation (new (5, 5), ViewportSettingsFlags.TransparentMouse); Assert.Contains (found, v => v == secondaryToplevel); Assert.Contains (found, v => v == secondaryToplevel.Margin); Assert.DoesNotContain (found, v => v?.Id == topToplevel.Id); - secondaryToplevel.Margin.ViewportSettings = ViewportSettingsFlags.TransparentMouse; + secondaryToplevel.Margin!.ViewportSettings = ViewportSettingsFlags.TransparentMouse; found = View.GetViewsUnderLocation (new (5, 5), ViewportSettingsFlags.TransparentMouse); Assert.DoesNotContain (found, v => v == secondaryToplevel); Assert.DoesNotContain (found, v => v == secondaryToplevel.Margin); diff --git a/Tests/UnitTests/View/Layout/Pos.AnchorEndTests.cs b/Tests/UnitTests/View/Layout/Pos.AnchorEndTests.cs index bf5d19d47..80579a2c7 100644 --- a/Tests/UnitTests/View/Layout/Pos.AnchorEndTests.cs +++ b/Tests/UnitTests/View/Layout/Pos.AnchorEndTests.cs @@ -26,7 +26,7 @@ public class PosAnchorEndTests () top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); + Application.Driver!.SetScreenSize (80,25); Assert.Equal (new (0, 0, 80, 25), top.Frame); Assert.Equal (new (0, 0, 80, 25), win.Frame); diff --git a/Tests/UnitTests/View/Layout/Pos.CenterTests.cs b/Tests/UnitTests/View/Layout/Pos.CenterTests.cs index 2a4405a1d..0b094f262 100644 --- a/Tests/UnitTests/View/Layout/Pos.CenterTests.cs +++ b/Tests/UnitTests/View/Layout/Pos.CenterTests.cs @@ -33,9 +33,8 @@ public class PosCenterTests (ITestOutputHelper output) win.Add (subview); RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(20, height)); + Application.Driver!.SetScreenSize (20, height); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; @@ -180,9 +179,8 @@ public class PosCenterTests (ITestOutputHelper output) win.Add (subview); RunState rs = Application.Begin (win); - var firstIteration = false; - AutoInitShutdownAttribute.FakeResize(new Size(width, 7)); + Application.Driver!.SetScreenSize (width, 7); AutoInitShutdownAttribute.RunIteration (); var expected = string.Empty; diff --git a/Tests/UnitTests/View/Layout/SetLayoutTests.cs b/Tests/UnitTests/View/Layout/SetLayoutTests.cs index d259837b3..ac3654e29 100644 --- a/Tests/UnitTests/View/Layout/SetLayoutTests.cs +++ b/Tests/UnitTests/View/Layout/SetLayoutTests.cs @@ -25,13 +25,13 @@ public class SetLayoutTests (ITestOutputHelper output) Application.Top.Add (view); var rs = Application.Begin (Application.Top); - AutoInitShutdownAttribute.FakeResize (new Size (80,25)); + Application.Driver!.SetScreenSize (80, 25); Assert.Equal (new (0, 0, 80, 25), new Rectangle (0, 0, Application.Screen.Width, Application.Screen.Height)); Assert.Equal (new (0, 0, Application.Screen.Width, Application.Screen.Height), Application.Top.Frame); Assert.Equal (new (0, 0, 80, 25), Application.Top.Frame); - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)) ; + Application.Driver!.SetScreenSize (20, 10); Assert.Equal (new (0, 0, Application.Screen.Width, Application.Screen.Height), Application.Top.Frame); Assert.Equal (new (0, 0, 20, 10), Application.Top.Frame); diff --git a/Tests/UnitTests/View/Mouse/MouseTests.cs b/Tests/UnitTests/View/Mouse/MouseTests.cs index 8b9732b37..792cbb216 100644 --- a/Tests/UnitTests/View/Mouse/MouseTests.cs +++ b/Tests/UnitTests/View/Mouse/MouseTests.cs @@ -1,5 +1,4 @@ -using Moq; -using UnitTests; +using Timeout = Terminal.Gui.App.Timeout; namespace UnitTests.ViewMouseTests; @@ -35,8 +34,8 @@ public class MouseTests : TestsAllViews Height = 10, Arrangement = ViewArrangement.Movable }; - testView.Margin.Thickness = new (marginThickness); - testView.Border.Thickness = new (borderThickness); + testView.Margin!.Thickness = new (marginThickness); + testView.Border!.Thickness = new (borderThickness); testView.Padding.Thickness = new (paddingThickness); var top = new Toplevel (); @@ -187,7 +186,7 @@ public class MouseTests : TestsAllViews view.MouseHeldDown.MouseIsHeldDownTick += (_, _) => clickedCount++; // Mouse is currently not held down so should be no timers running - Assert.Empty(timed.Timeouts); + Assert.Empty (timed.Timeouts); // When mouse is held down me.Flags = pressed; @@ -196,14 +195,14 @@ public class MouseTests : TestsAllViews me.Handled = false; // A timer should begin - var t = Assert.Single (timed.Timeouts); + KeyValuePair t = Assert.Single (timed.Timeouts); // Invoke the timer t.Value.Callback.Invoke (); // Event should have been raised Assert.Equal (1, clickedCount); - Assert.NotEmpty(timed.Timeouts); + Assert.NotEmpty (timed.Timeouts); // When mouse is released me.Flags = released; @@ -253,7 +252,7 @@ public class MouseTests : TestsAllViews Assert.Equal (0, clickedCount); me.Handled = false; - Assert.NotEmpty(timed.Timeouts); + Assert.NotEmpty (timed.Timeouts); Assert.Single (timed.Timeouts).Value.Callback.Invoke (); me.Flags = pressed; @@ -308,7 +307,7 @@ public class MouseTests : TestsAllViews // Mouse is held down so timer should be ticking Assert.NotEmpty (timed.Timeouts); - Assert.Equal (clickedCount,0); + Assert.Equal (clickedCount, 0); // Don't wait, just force it to expire Assert.Single (timed.Timeouts).Value.Callback.Invoke (); @@ -571,7 +570,6 @@ public class MouseTests : TestsAllViews Application.ResetState (true); } - [Theory] [InlineData (0)] [InlineData (1)] @@ -634,6 +632,7 @@ public class MouseTests : TestsAllViews // Button1Pressed, Button1Released cause Application.Mouse.MouseGrabView to be set Application.ResetState (true); } + private class MouseEventTestView : View { public int MouseEnterCount { get; private set; } diff --git a/Tests/UnitTests/View/TextTests.cs b/Tests/UnitTests/View/TextTests.cs index f8062c744..ab220c8f0 100644 --- a/Tests/UnitTests/View/TextTests.cs +++ b/Tests/UnitTests/View/TextTests.cs @@ -121,11 +121,11 @@ Y top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(15, 15)) ; + Application.Driver!.SetScreenSize (15, 15); Assert.Equal (new (0, 0, 15, 15), win.Frame); - Assert.Equal (new (0, 0, 15, 15), win.Margin.Frame); - Assert.Equal (new (0, 0, 15, 15), win.Border.Frame); + Assert.Equal (new (0, 0, 15, 15), win.Margin!.Frame); + Assert.Equal (new (0, 0, 15, 15), win.Border!.Frame); Assert.Equal (new (1, 1, 13, 13), win.Padding.Frame); Assert.Equal (TextDirection.LeftRight_TopBottom, view.TextDirection); @@ -386,7 +386,7 @@ Y var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(4, 10)); + Application.Driver!.SetScreenSize (4, 10); Assert.Equal (5, text.Length); @@ -511,7 +511,7 @@ w "; var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(20, 20)); + Application.Driver!.SetScreenSize (20, 20); Assert.Equal (new (0, 0, 11, 2), horizontalView.Frame); Assert.Equal (new (0, 3, 2, 11), verticalView.Frame); @@ -599,7 +599,7 @@ w "; var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(22, 22)); + Application.Driver!.SetScreenSize (22, 22); Assert.Equal (new (text.GetColumns (), 1), horizontalView.TextFormatter.ConstrainToSize); Assert.Equal (new (2, 8), verticalView.TextFormatter.ConstrainToSize); @@ -783,7 +783,7 @@ w "; var top = new Toplevel (); top.Add (frame); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size(width + 2, 6)); + Application.Driver!.SetScreenSize (width + 2, 6); // frame.Width is width + border wide (20 + 2) and 6 high @@ -913,7 +913,7 @@ w "; var top = new Toplevel (); top.Add (frame); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(9, height + 2)); + Application.Driver!.SetScreenSize (9, height + 2); if (autoSize) { @@ -998,7 +998,7 @@ w "; [SetupFakeDriver] public void Narrow_Wide_Runes () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (32, 32); + Application.Driver!.SetScreenSize (32, 32); var top = new View { Width = 32, Height = 32 }; var text = $"First line{Environment.NewLine}Second line"; diff --git a/Tests/UnitTests/View/ViewTests.cs b/Tests/UnitTests/View/ViewTests.cs index c2b62059a..466a292d1 100644 --- a/Tests/UnitTests/View/ViewTests.cs +++ b/Tests/UnitTests/View/ViewTests.cs @@ -456,7 +456,7 @@ public class ViewTests AutoInitShutdownAttribute.RunIteration (); Assert.Equal ("Testing visibility.".Length, view.Frame.Width); Assert.True (view.Visible); - AutoInitShutdownAttribute.FakeResize(new Size(30, 5)); + Application.Driver!.SetScreenSize (30, 5); DriverAssert.AssertDriverContentsWithFrameAre ( @" diff --git a/Tests/UnitTests/Views/ButtonTests.cs b/Tests/UnitTests/Views/ButtonTests.cs index 002c1e7a3..6c958d538 100644 --- a/Tests/UnitTests/Views/ButtonTests.cs +++ b/Tests/UnitTests/Views/ButtonTests.cs @@ -1,3 +1,4 @@ +using TerminalGuiFluentTesting; using UnitTests; using Xunit.Abstractions; @@ -243,7 +244,7 @@ public class ButtonTests (ITestOutputHelper output) Assert.False (btn.IsInitialized); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(30, 5)); + Application.Driver?.SetScreenSize (30, 5); Assert.True (btn.IsInitialized); Assert.Equal ("Say Hello 你", btn.Text); diff --git a/Tests/UnitTests/Views/CheckBoxTests.cs b/Tests/UnitTests/Views/CheckBoxTests.cs index ff575a779..22166d6a9 100644 --- a/Tests/UnitTests/Views/CheckBoxTests.cs +++ b/Tests/UnitTests/Views/CheckBoxTests.cs @@ -96,7 +96,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (30, 5)); + Application.Driver?.SetScreenSize (30, 5); Assert.Equal (Alignment.Center, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); @@ -156,7 +156,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(30, 6)); + Application.Driver!.SetScreenSize (30, 6); Assert.Equal (Alignment.Fill, checkBox1.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox1.Frame); @@ -217,7 +217,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(30, 5)); + Application.Driver!.SetScreenSize (30, 5); Assert.Equal (Alignment.Start, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); @@ -268,7 +268,7 @@ public class CheckBoxTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(30, 5)); + Application.Driver!.SetScreenSize (30, 5); Assert.Equal (Alignment.End, checkBox.TextAlignment); Assert.Equal (new (1, 1, 25, 1), checkBox.Frame); diff --git a/Tests/UnitTests/Views/FrameViewTests.cs b/Tests/UnitTests/Views/FrameViewTests.cs index 5f6bda9c1..2b78d216b 100644 --- a/Tests/UnitTests/Views/FrameViewTests.cs +++ b/Tests/UnitTests/Views/FrameViewTests.cs @@ -13,12 +13,12 @@ public class FrameViewTests (ITestOutputHelper output) Assert.Equal (string.Empty, fv.Text); Assert.Equal (LineStyle.Rounded, fv.BorderStyle); - fv = new() { Title = "Test" }; + fv = new () { Title = "Test" }; Assert.Equal ("Test", fv.Title); Assert.Equal (string.Empty, fv.Text); Assert.Equal (LineStyle.Rounded, fv.BorderStyle); - fv = new() + fv = new () { X = 1, Y = 2, @@ -38,7 +38,7 @@ public class FrameViewTests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_Defaults () { - AutoInitShutdownAttribute.FakeResize(new Size(10, 10)); + Application.Driver!.SetScreenSize (10, 10); var fv = new FrameView () { BorderStyle = LineStyle.Single }; Assert.Equal (string.Empty, fv.Title); Assert.Equal (string.Empty, fv.Text); diff --git a/Tests/UnitTests/Views/LabelTests.cs b/Tests/UnitTests/Views/LabelTests.cs index aacc98efd..9ea2daca2 100644 --- a/Tests/UnitTests/Views/LabelTests.cs +++ b/Tests/UnitTests/Views/LabelTests.cs @@ -18,7 +18,7 @@ public class LabelTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (30, 5)); + Application.Driver!.SetScreenSize (30, 5); AutoInitShutdownAttribute.RunIteration (); var expected = @" @@ -59,7 +59,7 @@ public class LabelTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (30, 5)); + Application.Driver!.SetScreenSize (30, 5); var expected = @" ┌────────────────────────────┐ @@ -245,7 +245,7 @@ e Assert.False (label.IsInitialized); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (30, 5)); + Application.Driver!.SetScreenSize (30, 5); Assert.True (label.IsInitialized); Assert.Equal ("Say Hello 你", label.Text); @@ -277,7 +277,7 @@ e Assert.False (label.IsInitialized); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (30, 5)); + Application.Driver!.SetScreenSize (30, 5); Assert.True (label.IsInitialized); Assert.Equal ("Say Hello 你", label.Text); @@ -326,8 +326,8 @@ e public void With_Top_Margin_Without_Top_Border () { var label = new Label { Text = "Test", /*Width = 6, Height = 3,*/ BorderStyle = LineStyle.Single }; - label.Margin.Thickness = new (0, 1, 0, 0); - label.Border.Thickness = new (1, 0, 1, 1); + label.Margin!.Thickness = new (0, 1, 0, 0); + label.Border!.Thickness = new (1, 0, 1, 1); var top = new Toplevel (); top.Add (label); Application.Begin (top); @@ -351,7 +351,7 @@ e public void Without_Top_Border () { var label = new Label { Text = "Test", /* Width = 6, Height = 3, */BorderStyle = LineStyle.Single }; - label.Border.Thickness = new (1, 0, 1, 1); + label.Border!.Thickness = new (1, 0, 1, 1); var top = new Toplevel (); top.Add (label); Application.Begin (top); @@ -709,7 +709,7 @@ e Toplevel top = new (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (40, 10)); + Application.Driver!.SetScreenSize (40, 10); Assert.Equal (29, label.Text.Length); Assert.Equal (new (0, 0, 40, 10), top.Frame); @@ -756,7 +756,7 @@ e Toplevel top = new (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (40, 10)); + Application.Driver!.SetScreenSize (40, 10); Assert.Equal (new (0, 0, 40, 10), top.Frame); Assert.Equal (new (0, 0, 40, 10), win.Frame); @@ -828,7 +828,7 @@ e { if (k.KeyCode == KeyCode.Enter) { - AutoInitShutdownAttribute.FakeResize (new Size (22, count + 4)); + Application.Driver!.SetScreenSize (22, count + 4); Rectangle pos = DriverAssert.AssertDriverContentsWithFrameAre (_expecteds [count], output); Assert.Equal (new (0, 0, 22, count + 4), pos); @@ -892,7 +892,7 @@ e [SetupFakeDriver] public void Label_Height_Zero_Stays_Zero () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (10, 4); + Application.Driver!.SetScreenSize (10, 4); var text = "Label"; var label = new Label @@ -979,7 +979,7 @@ e { if (k.KeyCode == KeyCode.Enter) { - AutoInitShutdownAttribute.FakeResize (new Size (22, count + 4)); + Application.Driver!.SetScreenSize (22, count + 4); Rectangle pos = DriverAssert.AssertDriverContentsWithFrameAre (_expecteds [count], output); Assert.Equal (new (0, 0, 22, count + 4), pos); @@ -1054,7 +1054,7 @@ e var top = new Toplevel (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (10, 4)); + Application.Driver!.SetScreenSize (10, 4); Assert.Equal (5, text.Length); Assert.Equal (new (0, 0, 5, 1), label.Frame); @@ -1113,7 +1113,7 @@ e var top = new Toplevel (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize (new Size (10, 4)); + Application.Driver!.SetScreenSize (10, 4); Assert.Equal (5, text.Length); Assert.Equal (new (0, 0, 5, 1), label.Frame); diff --git a/Tests/UnitTests/Views/ListViewTests.cs b/Tests/UnitTests/Views/ListViewTests.cs index 411538b46..2676dc1db 100644 --- a/Tests/UnitTests/Views/ListViewTests.cs +++ b/Tests/UnitTests/Views/ListViewTests.cs @@ -58,7 +58,7 @@ public class ListViewTests (ITestOutputHelper output) var top = new Toplevel (); top.Add (win); RunState rs = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(12, 12)); + Application.Driver!.SetScreenSize (12, 12); AutoInitShutdownAttribute.RunIteration (); Assert.Equal (-1, lv.SelectedItem); @@ -790,7 +790,7 @@ Item 6", Application.Begin (top); AutoInitShutdownAttribute.RunIteration (); - Assert.Equal (new (1), lv.Border.Thickness); + Assert.Equal (new (1), lv.Border!.Thickness); Assert.Equal (-1, lv.SelectedItem); Assert.Equal ("", lv.Text); diff --git a/Tests/UnitTests/Views/Menuv1/MenuBarv1Tests.cs b/Tests/UnitTests/Views/Menuv1/MenuBarv1Tests.cs index e81512510..c334d32f6 100644 --- a/Tests/UnitTests/Views/Menuv1/MenuBarv1Tests.cs +++ b/Tests/UnitTests/Views/Menuv1/MenuBarv1Tests.cs @@ -470,7 +470,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) Window win = new (); top.Add (win); RunState rsTop = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(40, 15)) ; + Application.Driver!.SetScreenSize (40, 15); Assert.Equal (new (0, 0, 40, 15), win.Frame); @@ -656,7 +656,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) Assert.Equal (items [i], menu.Menus [0].Title); } - AutoInitShutdownAttribute.FakeResize(new Size(20, 15)); + Application.Driver!.SetScreenSize (20, 15); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -689,7 +689,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) [AutoInitShutdown] public void Draw_A_Menu_Over_A_Top_Dialog () { - ((FakeDriver)Application.Driver).SetBufferSize (40, 15); + Application.Driver!.SetScreenSize (40, 15); // Override CM Window.DefaultBorderStyle = LineStyle.Single; @@ -836,7 +836,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) Assert.Equal (items [i], menu.Menus [0].Title); } - AutoInitShutdownAttribute.FakeResize(new Size(20, 15)); + Application.Driver!.SetScreenSize (20, 15); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -907,7 +907,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - AutoInitShutdownAttribute.FakeResize(new Size(7, 5)); + Application.Driver!.SetScreenSize (7, 5); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -923,7 +923,7 @@ public class MenuBarv1Tests (ITestOutputHelper output) menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - AutoInitShutdownAttribute.FakeResize(new Size(7, 3)); + Application.Driver!.SetScreenSize (7, 3); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -981,7 +981,7 @@ wo menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - AutoInitShutdownAttribute.FakeResize(new Size(3, 2)); + Application.Driver!.SetScreenSize (3, 2); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -994,7 +994,7 @@ wo menu.CloseAllMenus (); menu.Frame = new (0, 0, menu.Frame.Width, menu.Frame.Height); - AutoInitShutdownAttribute.FakeResize(new Size(3, 1)); + Application.Driver!.SetScreenSize (3, 1); menu.OpenMenu (); AutoInitShutdownAttribute.RunIteration (); @@ -1628,7 +1628,7 @@ wo Toplevel top = new (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(40, 8)); + Application.Driver!.SetScreenSize (40, 8); DriverAssert.AssertDriverContentsWithFrameAre ( @" @@ -1740,7 +1740,7 @@ wo Application.AddTimeout (TimeSpan.Zero, () => { - AutoInitShutdownAttribute.FakeResize(new Size (40, 8)); + Application.Driver!.SetScreenSize (40, 8); DriverAssert.AssertDriverContentsWithFrameAre ( @" @@ -1854,7 +1854,7 @@ wo ] }; win.Add (menu); - AutoInitShutdownAttribute.FakeResize(new Size(40, 8)); + Application.Driver!.SetScreenSize (40, 8); RunState rs = Application.Begin (win); AutoInitShutdownAttribute.RunIteration (); @@ -1941,7 +1941,7 @@ wo [AutoInitShutdown] public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () { - AutoInitShutdownAttribute.FakeResize(new Size(40, 8)); + Application.Driver!.SetScreenSize (40, 8); Application.AddTimeout (TimeSpan.Zero, () => { @@ -2897,7 +2897,7 @@ Edit output ); - AutoInitShutdownAttribute.FakeResize(new Size(20, 15)); + Application.Driver!.SetScreenSize (20, 15); AutoInitShutdownAttribute.RunIteration (); diff --git a/Tests/UnitTests/Views/RadioGroupTests.cs b/Tests/UnitTests/Views/RadioGroupTests.cs index cf10e5bab..07f0adf6a 100644 --- a/Tests/UnitTests/Views/RadioGroupTests.cs +++ b/Tests/UnitTests/Views/RadioGroupTests.cs @@ -533,7 +533,7 @@ public class RadioGroupTests (ITestOutputHelper output) top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(30, 5)); + Application.Driver!.SetScreenSize (30, 5); Assert.Equal (Orientation.Vertical, rg.Orientation); Assert.Equal (2, rg.RadioLabels.Length); diff --git a/Tests/UnitTests/Views/TableViewTests.cs b/Tests/UnitTests/Views/TableViewTests.cs index 27d77328c..dccc58d46 100644 --- a/Tests/UnitTests/Views/TableViewTests.cs +++ b/Tests/UnitTests/Views/TableViewTests.cs @@ -2206,7 +2206,7 @@ public class TableViewTests (ITestOutputHelper output) [SetupFakeDriver] public void TestEnumerableDataSource_BasicTypes () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (100, 100); + Application.Driver!.SetScreenSize (100, 100); var tv = new TableView (); tv.SchemeName = "TopLevel"; tv.Viewport = new (0, 0, 50, 6); diff --git a/Tests/UnitTests/Views/TextFieldTests.cs b/Tests/UnitTests/Views/TextFieldTests.cs index 123201f49..d6cbae340 100644 --- a/Tests/UnitTests/Views/TextFieldTests.cs +++ b/Tests/UnitTests/Views/TextFieldTests.cs @@ -10,73 +10,6 @@ public class TextFieldTests (ITestOutputHelper output) { private static TextField _textField; - [Fact] - [SetupFakeDriver] - public void Accented_Letter_With_Three_Combining_Unicode_Chars () - { - var tf = new TextField { Width = 3, Text = "ắ" }; - tf.Layout (); - tf.Draw (); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -ắ", - output - ); - - tf.Text = "\u1eaf"; - tf.Layout (); - tf.Draw (); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -ắ", - output - ); - - tf.Text = "\u0103\u0301"; - tf.Layout (); - tf.Draw (); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -ắ", - output - ); - - tf.Text = "\u0061\u0306\u0301"; - tf.Layout (); - tf.Draw (); - - DriverAssert.AssertDriverContentsWithFrameAre ( - @" -ắ", - output - ); - } - - [Fact] - [SetupFakeDriver] - public void Adjust_First () - { - var tf = new TextField { Width = Dim.Fill (), Text = "This is a test." }; - tf.SetRelativeLayout (new (20, 20)); - tf.Draw (); - - Assert.Equal ("This is a test. ", GetContents ()); - - string GetContents () - { - var item = ""; - - for (var i = 0; i < 16; i++) - { - item += Application.Driver?.Contents [0, i].Rune; - } - - return item; - } - } [Fact] [TextFieldTestsAutoInitShutdown] diff --git a/Tests/UnitTests/Views/TextViewTests.cs b/Tests/UnitTests/Views/TextViewTests.cs index 6d63b3b07..d09f7e8b2 100644 --- a/Tests/UnitTests/Views/TextViewTests.cs +++ b/Tests/UnitTests/Views/TextViewTests.cs @@ -5262,7 +5262,7 @@ TAB to jump between text field", var top = new Toplevel (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(15, 15)); + Application.Driver!.SetScreenSize (15, 15); AutoInitShutdownAttribute.RunIteration (); //this passes @@ -5340,7 +5340,7 @@ TAB to jump between text field", var top = new Toplevel (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size (15, 15)); + Application.Driver!.SetScreenSize (15, 15); AutoInitShutdownAttribute.RunIteration (); //this passes @@ -5453,7 +5453,7 @@ This is the second line. _output ); - AutoInitShutdownAttribute.FakeResize(new Size (6, 25)); + Application.Driver!.SetScreenSize (6, 25); tv.SetRelativeLayout (Application.Screen.Size); tv.Draw (); Assert.Equal (new (4, 2), tv.CursorPosition); diff --git a/Tests/UnitTests/Views/ToplevelTests.cs b/Tests/UnitTests/Views/ToplevelTests.cs index 3160fb314..7aba89b6e 100644 --- a/Tests/UnitTests/Views/ToplevelTests.cs +++ b/Tests/UnitTests/Views/ToplevelTests.cs @@ -1,6 +1,4 @@ -using UnitTests; - -namespace UnitTests.ViewsTests; +namespace UnitTests.ViewsTests; public class ToplevelTests { @@ -285,7 +283,7 @@ public class ToplevelTests if (iterations == 0) { - AutoInitShutdownAttribute.FakeResize(new Size(15, 7)); + Application.Driver?.SetScreenSize (15, 7); // Don't use MessageBox here; it's too complicated for this unit test; just use Window testWindow = new () @@ -405,7 +403,7 @@ public class ToplevelTests if (iterations == 0) { - AutoInitShutdownAttribute.FakeResize(new Size(30, 10)); + Application.Driver?.SetScreenSize (30, 10); } else if (iterations == 1) { @@ -507,10 +505,10 @@ public class ToplevelTests top.BeginInit (); top.EndInit (); - Exception exception = Record.Exception (() => ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (0, 10)); + Exception exception = Record.Exception (() => Application.Driver!.SetScreenSize (0, 10)); Assert.Null (exception); - exception = Record.Exception (() => ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (10, 0)); + exception = Record.Exception (() => Application.Driver!.SetScreenSize (10, 0)); Assert.Null (exception); } @@ -596,7 +594,8 @@ public class ToplevelTests Toplevel top = new (); var window = new Window { Width = 20, Height = 3, Arrangement = ViewArrangement.Movable }; RunState rsTop = Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(40, 10)); + Application.Driver?.SetScreenSize (40, 10); + RunState rsWindow = Application.Begin (window); AutoInitShutdownAttribute.RunIteration (); Assert.Equal (new (0, 0, 40, 10), top.Frame); @@ -619,7 +618,7 @@ public class ToplevelTests Assert.Equal (new (-11, -4, 20, 3), window.Frame); // Changes Top size to same size as Dialog more menu and scroll bar - AutoInitShutdownAttribute.FakeResize(new Size(20, 3)); + Application.Driver?.SetScreenSize (20, 3); Application.RaiseMouseEvent ( new () @@ -632,7 +631,7 @@ public class ToplevelTests Assert.Equal (new (-1, -1, 20, 3), window.Frame); // Changes Top size smaller than Dialog size - AutoInitShutdownAttribute.FakeResize(new Size(19, 2)); + Application.Driver?.SetScreenSize (19, 2); Application.RaiseMouseEvent ( new () @@ -699,7 +698,6 @@ public class ToplevelTests Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed }); - var firstIteration = false; AutoInitShutdownAttribute.RunIteration (); Assert.Equal (window.Border, Application.Mouse.MouseGrabView); @@ -711,7 +709,6 @@ public class ToplevelTests ScreenPosition = new (1, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition }); - firstIteration = false; AutoInitShutdownAttribute.RunIteration (); Assert.Equal (window.Border, Application.Mouse.MouseGrabView); Assert.Equal (new (1, 1, 10, 3), window.Frame); diff --git a/Tests/UnitTests/Views/TreeTableSourceTests.cs b/Tests/UnitTests/Views/TreeTableSourceTests.cs index 6d3c972be..bd73e0452 100644 --- a/Tests/UnitTests/Views/TreeTableSourceTests.cs +++ b/Tests/UnitTests/Views/TreeTableSourceTests.cs @@ -30,7 +30,7 @@ public class TreeTableSourceTests : IDisposable [SetupFakeDriver] public void TestTreeTableSource_BasicExpanding_WithKeyboard () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (100, 100); + Application.Driver!.SetScreenSize (100, 100); TableView tv = GetTreeTable (out _); tv.Style.GetOrCreateColumnStyle (1).MinAcceptableWidth = 1; @@ -91,7 +91,7 @@ public class TreeTableSourceTests : IDisposable [SetupFakeDriver] public void TestTreeTableSource_BasicExpanding_WithMouse () { - ((IFakeConsoleDriver)Application.Driver!).SetBufferSize (100, 100); + Application.Driver!.SetScreenSize (100, 100); TableView tv = GetTreeTable (out _); diff --git a/Tests/UnitTests/Views/WindowTests.cs b/Tests/UnitTests/Views/WindowTests.cs index a53aa43aa..32d524549 100644 --- a/Tests/UnitTests/Views/WindowTests.cs +++ b/Tests/UnitTests/Views/WindowTests.cs @@ -51,7 +51,7 @@ public class WindowTests (ITestOutputHelper output) Toplevel top = new (); top.Add (win); Application.Begin (top); - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize (20, 10); DriverAssert.AssertDriverContentsWithFrameAre ( @" @@ -68,7 +68,7 @@ public class WindowTests (ITestOutputHelper output) output ); - AutoInitShutdownAttribute.FakeResize(new Size(40, 20)); + Application.Driver!.SetScreenSize (40, 20); DriverAssert.AssertDriverContentsWithFrameAre ( @" @@ -95,7 +95,7 @@ public class WindowTests (ITestOutputHelper output) output ); - AutoInitShutdownAttribute.FakeResize(new Size(20, 10)); + Application.Driver!.SetScreenSize (20, 10); DriverAssert.AssertDriverContentsWithFrameAre ( @" @@ -168,8 +168,8 @@ public class WindowTests (ITestOutputHelper output) Assert.Equal (TextDirection.LeftRight_TopBottom, windowWithFrameRectEmpty.TextDirection); // Rect with values - using var windowWithFrame1234 = new Window ( ); - windowWithFrame1234.Frame = new (1, 2, 3, 4); + using var windowWithFrame1234 = new Window (); + windowWithFrame1234.Frame = new (1, 2, 3, 4); windowWithFrame1234.Title = "title"; Assert.Equal ("title", windowWithFrame1234.Title); Assert.NotNull (windowWithFrame1234); diff --git a/Tests/UnitTestsParallelizable/Application/MouseInterfaceTests.cs b/Tests/UnitTestsParallelizable/Application/MouseInterfaceTests.cs index 6cdc8d378..69b64f51a 100644 --- a/Tests/UnitTestsParallelizable/Application/MouseInterfaceTests.cs +++ b/Tests/UnitTestsParallelizable/Application/MouseInterfaceTests.cs @@ -1,3 +1,4 @@ +#nullable enable using Terminal.Gui.App; using Xunit.Abstractions; @@ -89,7 +90,7 @@ public class MouseInterfaceTests (ITestOutputHelper output) // Arrange MouseImpl mouse = new (); var eventFired = false; - MouseEventArgs capturedArgs = null; + MouseEventArgs? capturedArgs = null; mouse.MouseEvent += (sender, args) => { @@ -120,7 +121,7 @@ public class MouseInterfaceTests (ITestOutputHelper output) MouseImpl mouse = new (); var eventCount = 0; - void Handler (object sender, MouseEventArgs args) => eventCount++; + void Handler (object? sender, MouseEventArgs args) => eventCount++; mouse.MouseEvent += Handler; diff --git a/Tests/UnitTestsParallelizable/Input/EscSeqRequestsTests.cs b/Tests/UnitTestsParallelizable/ConsoleDrivers/EscSeqRequestsTests.cs similarity index 59% rename from Tests/UnitTestsParallelizable/Input/EscSeqRequestsTests.cs rename to Tests/UnitTestsParallelizable/ConsoleDrivers/EscSeqRequestsTests.cs index 0d86281a9..abb12e20c 100644 --- a/Tests/UnitTestsParallelizable/Input/EscSeqRequestsTests.cs +++ b/Tests/UnitTestsParallelizable/ConsoleDrivers/EscSeqRequestsTests.cs @@ -1,6 +1,8 @@ -namespace UnitTests_Parallelizable.DriverTests; +using UnitTests.Parallelizable; -public class EscSeqRequestsTests : UnitTests.Parallelizable.ParallelizableBase +namespace UnitTests_Parallelizable.DriverTests; + +public class EscSeqRequestsTests : ParallelizableBase { [Fact] public void Add_Tests () @@ -122,67 +124,4 @@ public class EscSeqRequestsTests : UnitTests.Parallelizable.ParallelizableBase EscSeqRequests.Clear (); } - - [Fact] - public void Requests_Responses_Tests () - { - // This is simulated response from a CSI_ReportTerminalSizeInChars - ConsoleKeyInfo [] cki = - [ - new ('\u001b', 0, false, false, false), - new ('[', 0, false, false, false), - new ('8', 0, false, false, false), - new (';', 0, false, false, false), - new ('1', 0, false, false, false), - new ('0', 0, false, false, false), - new (';', 0, false, false, false), - new ('2', 0, false, false, false), - new ('0', 0, false, false, false), - new ('t', 0, false, false, false) - ]; - ConsoleKeyInfo newConsoleKeyInfo = default; - ConsoleKey key = default; - ConsoleModifiers mod = default; - - Assert.Empty (EscSeqRequests.Statuses); - - EscSeqRequests.Add ("t"); - Assert.Single (EscSeqRequests.Statuses); - Assert.Equal ("t", EscSeqRequests.Statuses [^1].Terminator); - Assert.Equal (1, EscSeqRequests.Statuses [^1].NumRequests); - Assert.Equal (1, EscSeqRequests.Statuses [^1].NumOutstanding); - - EscSeqUtils.DecodeEscSeq ( - ref newConsoleKeyInfo, - ref key, - cki, - ref mod, - out string c1Control, - out string code, - out string [] values, - out string terminating, - out bool isKeyMouse, - out List mouseFlags, - out Point pos, - out bool isResponse, - null - ); - - Assert.Empty (EscSeqRequests.Statuses); - Assert.Equal (default, newConsoleKeyInfo); - Assert.Equal (default, key); - Assert.Equal (10, cki.Length); - Assert.Equal (default, mod); - Assert.Equal ("CSI", c1Control); - Assert.Null (code); - // ReSharper disable once HeuristicUnreachableCode - Assert.Equal (3, values.Length); - Assert.Equal ("8", values [0]); - Assert.Equal ("t", terminating); - Assert.False (isKeyMouse); - Assert.Single (mouseFlags); - Assert.Equal (default, mouseFlags [^1]); - Assert.Equal (Point.Empty, pos); - Assert.True (isResponse); - } } diff --git a/Tests/UnitTestsParallelizable/ConsoleDrivers/UrlHyperlinkerTests.cs b/Tests/UnitTestsParallelizable/ConsoleDrivers/UrlHyperlinkerTests.cs index 5d9e46b5c..b09eb5555 100644 --- a/Tests/UnitTestsParallelizable/ConsoleDrivers/UrlHyperlinkerTests.cs +++ b/Tests/UnitTestsParallelizable/ConsoleDrivers/UrlHyperlinkerTests.cs @@ -2,7 +2,7 @@ using System.Text; using Xunit.Abstractions; -namespace Terminal.Gui.DriverTests; +namespace UnitTests_Parallelizable.ConoleDriverTests; public class Osc8UrlLinkerTests (ITestOutputHelper output) { diff --git a/Tests/UnitTestsParallelizable/Drawing/AttributeTests.cs b/Tests/UnitTestsParallelizable/Drawing/AttributeTests.cs index 7dd6858ec..ac3d1d70c 100644 --- a/Tests/UnitTestsParallelizable/Drawing/AttributeTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/AttributeTests.cs @@ -217,24 +217,6 @@ public class AttributeTests Assert.Equal (attr1.GetHashCode (), attr2.GetHashCode ()); } - [Fact] - public void Implicit_Assign () - { - var driver = new FakeDriver (); - driver.Init (); - - var attr = new Attribute (); - - var value = 42; - var fg = new Color (); - fg = new (Color.Red); - - var bg = new Color (); - bg = new (Color.Blue); - - driver.End (); - } - [Fact] public void InequalityOperator_ShouldReturnFalseForEqualAttributes () { diff --git a/Tests/UnitTestsParallelizable/Drawing/LineCanvasTests.cs b/Tests/UnitTestsParallelizable/Drawing/LineCanvasTests.cs index 065037028..d86e03d13 100644 --- a/Tests/UnitTestsParallelizable/Drawing/LineCanvasTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/LineCanvasTests.cs @@ -1,13 +1,17 @@ +using System.Text; +using UnitTests; +using UnitTests.Parallelizable; +using Xunit.Abstractions; + namespace UnitTests_Parallelizable.DrawingTests; /// -/// Pure unit tests for that don't require Application.Driver or View context. -/// These tests focus on properties and behavior that don't depend on glyph rendering. -/// -/// Note: Tests that verify rendered output (ToString()) cannot be parallelized because LineCanvas -/// depends on Application.Driver for glyph resolution and configuration. Those tests remain in UnitTests. +/// Pure unit tests for that don't require Application.Driver or View context. +/// These tests focus on properties and behavior that don't depend on glyph rendering. +/// Note: Tests that verify rendered output (ToString()) cannot be parallelized because LineCanvas +/// depends on Application.Driver for glyph resolution and configuration. Those tests remain in UnitTests. /// -public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase +public class LineCanvasTests (ITestOutputHelper output) : ParallelizableBase { #region Basic API Tests @@ -58,7 +62,7 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase [Fact] public void Constructor_With_Lines_Creates_Canvas_With_Lines () { - var lines = new[] + StraightLine [] lines = new [] { new StraightLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single), new StraightLine (new (0, 0), 3, Orientation.Vertical, LineStyle.Single) @@ -188,12 +192,16 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase public void Bounds_Complex_Box () { var canvas = new LineCanvas (); + // top canvas.AddLine (new (0, 0), 3, Orientation.Horizontal, LineStyle.Single); + // left canvas.AddLine (new (0, 0), 2, Orientation.Vertical, LineStyle.Single); + // right canvas.AddLine (new (2, 0), 2, Orientation.Vertical, LineStyle.Single); + // bottom canvas.AddLine (new (0, 2), 3, Orientation.Horizontal, LineStyle.Single); @@ -210,12 +218,12 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase var canvas = new LineCanvas (); canvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); - var region = new Region (new Rectangle (0, 0, 2, 1)); + var region = new Region (new (0, 0, 2, 1)); canvas.Exclude (region); canvas.ClearExclusions (); // After clearing exclusions, GetMap should return all points - var map = canvas.GetMap (); + Dictionary map = canvas.GetMap (); Assert.Equal (5, map.Count); } @@ -225,10 +233,11 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase var canvas = new LineCanvas (); canvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); - var region = new Region (new Rectangle (0, 0, 2, 1)); + var region = new Region (new (0, 0, 2, 1)); canvas.Exclude (region); - var map = canvas.GetMap (); + Dictionary map = canvas.GetMap (); + // Should have 5 - 2 = 3 points (excluding the first 2) Assert.Equal (3, map.Count); } @@ -240,8 +249,8 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase [Fact] public void Fill_Property_Can_Be_Set () { - var foregroundFill = new SolidFill (new Color (255, 0)); - var backgroundFill = new SolidFill (new Color (0, 0)); + var foregroundFill = new SolidFill (new (255, 0)); + var backgroundFill = new SolidFill (new (0, 0)); var fillPair = new FillPair (foregroundFill, backgroundFill); var canvas = new LineCanvas { Fill = fillPair }; @@ -257,4 +266,1246 @@ public class LineCanvasTests : UnitTests.Parallelizable.ParallelizableBase } #endregion + + [Theory] + + // Horizontal lines with a vertical zero-length + [InlineData ( + 0, + 0, + 1, + Orientation.Horizontal, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + "╞" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Horizontal, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + "╡" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Horizontal, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + "╟" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Horizontal, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + "╢" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Horizontal, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + "├" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Horizontal, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + "┤" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Horizontal, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + "╠" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Horizontal, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + "╣" + )] + + // Vertical lines with a horizontal zero-length + [InlineData ( + 0, + 0, + 1, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "╥" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "╨" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╤" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╧" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "┬" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "┴" + )] + [InlineData ( + 0, + 0, + 1, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╦" + )] + [InlineData ( + 0, + 0, + -1, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╩" + )] + + // Crosses (two zero-length) + [InlineData ( + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "╫" + )] + [InlineData ( + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╪" + )] + [InlineData ( + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Single, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Single, + "┼" + )] + [InlineData ( + 0, + 0, + 0, + Orientation.Vertical, + LineStyle.Double, + 0, + 0, + 0, + Orientation.Horizontal, + LineStyle.Double, + "╬" + )] + public void Add_2_Lines ( + int x1, + int y1, + int len1, + Orientation o1, + LineStyle s1, + int x2, + int y2, + int len2, + Orientation o2, + LineStyle s2, + string expected + ) + { + IConsoleDriver driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas lc); + v.Width = 10; + v.Height = 10; + v.Viewport = new (0, 0, 10, 10); + + lc.AddLine (new (x1, y1), len1, o1, s1); + lc.AddLine (new (x2, y2), len2, o2, s2); + + OutputAssert.AssertEqual (output, expected, lc.ToString ()); + v.Dispose (); + } + + + [Fact] + public void Viewport_Specific () + { + // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1) + // This proves we aren't drawing excess above + var x = 1; + var y = 2; + var width = 3; + var height = 2; + + var lc = new LineCanvas (); + + // 01230 + // ╔╡╞╗1 + // ║ ║2 + + // Add a short horiz line for ╔╡ + lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); + Assert.Equal (new (x, y, 2, 1), lc.Bounds); + + //LHS line down + lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); + Assert.Equal (new (x, y, 2, 2), lc.Bounds); + + //Vertical line before Title, results in a ╡ + lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); + Assert.Equal (new (x, y, 2, 2), lc.Bounds); + + //Vertical line after Title, results in a ╞ + lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); + Assert.Equal (new (x, y, 3, 2), lc.Bounds); + + // remainder of top line + lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); + Assert.Equal (new (x, y, 4, 2), lc.Bounds); + + //RHS line down + lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); + Assert.Equal (new (x, y, 4, 2), lc.Bounds); + + OutputAssert.AssertEqual ( + output, + @" +╔╡╞╗ +║ ║", + $"{Environment.NewLine}{lc}" + ); + } + + [Fact] + public void Viewport_Specific_With_Ustring () + { + // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1) + // This proves we aren't drawing excess above + var x = 1; + var y = 2; + var width = 3; + var height = 2; + + var lc = new LineCanvas (); + + // 01230 + // ╔╡╞╗1 + // ║ ║2 + + // Add a short horiz line for ╔╡ + lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); + Assert.Equal (new (x, y, 2, 1), lc.Bounds); + + //LHS line down + lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); + Assert.Equal (new (x, y, 2, 2), lc.Bounds); + + //Vertical line before Title, results in a ╡ + lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); + Assert.Equal (new (x, y, 2, 2), lc.Bounds); + + //Vertical line after Title, results in a ╞ + lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); + Assert.Equal (new (x, y, 3, 2), lc.Bounds); + + // remainder of top line + lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); + Assert.Equal (new (x, y, 4, 2), lc.Bounds); + + //RHS line down + lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); + Assert.Equal (new (x, y, 4, 2), lc.Bounds); + + OutputAssert.AssertEqual ( + output, + @" +╔╡╞╗ +║ ║", + $"{Environment.NewLine}{lc}" + ); + } + + [Fact] + public void Canvas_Updates_On_Changes () + { + var lc = new LineCanvas (); + + Assert.Equal (Rectangle.Empty, lc.Bounds); + + lc.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Double); + Assert.NotEqual (Rectangle.Empty, lc.Bounds); + + lc.Clear (); + Assert.Equal (Rectangle.Empty, lc.Bounds); + } + + [InlineData (0, 0, Orientation.Horizontal, "─")] + [InlineData (1, 0, Orientation.Horizontal, "─")] + [InlineData (0, 1, Orientation.Horizontal, "─")] + [InlineData (-1, 0, Orientation.Horizontal, "─")] + [InlineData (0, -1, Orientation.Horizontal, "─")] + [InlineData (-1, -1, Orientation.Horizontal, "─")] + [InlineData (0, 0, Orientation.Vertical, "│")] + [InlineData (1, 0, Orientation.Vertical, "│")] + [InlineData (0, 1, Orientation.Vertical, "│")] + [InlineData (0, -1, Orientation.Vertical, "│")] + [InlineData (-1, 0, Orientation.Vertical, "│")] + [InlineData (-1, -1, Orientation.Vertical, "│")] + [Theory] + public void Length_0_Is_1_Long (int x, int y, Orientation orientation, string expected) + { + var canvas = new LineCanvas (); + + // Add a line at 5, 5 that's has length of 1 + canvas.AddLine (new (x, y), 1, orientation, LineStyle.Single); + OutputAssert.AssertEqual (output, $"{expected}", $"{canvas}"); + } + + // X is offset by 2 + [InlineData (0, 0, 1, Orientation.Horizontal, "─")] + [InlineData (1, 0, 1, Orientation.Horizontal, "─")] + [InlineData (0, 1, 1, Orientation.Horizontal, "─")] + [InlineData (0, 0, 1, Orientation.Vertical, "│")] + [InlineData (1, 0, 1, Orientation.Vertical, "│")] + [InlineData (0, 1, 1, Orientation.Vertical, "│")] + [InlineData (-1, 0, 1, Orientation.Horizontal, "─")] + [InlineData (0, -1, 1, Orientation.Horizontal, "─")] + [InlineData (-1, 0, 1, Orientation.Vertical, "│")] + [InlineData (0, -1, 1, Orientation.Vertical, "│")] + [InlineData (0, 0, -1, Orientation.Horizontal, "─")] + [InlineData (1, 0, -1, Orientation.Horizontal, "─")] + [InlineData (0, 1, -1, Orientation.Horizontal, "─")] + [InlineData (0, 0, -1, Orientation.Vertical, "│")] + [InlineData (1, 0, -1, Orientation.Vertical, "│")] + [InlineData (0, 1, -1, Orientation.Vertical, "│")] + [InlineData (-1, 0, -1, Orientation.Horizontal, "─")] + [InlineData (0, -1, -1, Orientation.Horizontal, "─")] + [InlineData (-1, 0, -1, Orientation.Vertical, "│")] + [InlineData (0, -1, -1, Orientation.Vertical, "│")] + [InlineData (0, 0, 2, Orientation.Horizontal, "──")] + [InlineData (1, 0, 2, Orientation.Horizontal, "──")] + [InlineData (0, 1, 2, Orientation.Horizontal, "──")] + [InlineData (1, 1, 2, Orientation.Horizontal, "──")] + [InlineData (0, 0, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (1, 0, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (0, 1, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (1, 1, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (-1, 0, 2, Orientation.Horizontal, "──")] + [InlineData (0, -1, 2, Orientation.Horizontal, "──")] + [InlineData (-1, 0, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (0, -1, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (-1, -1, 2, Orientation.Vertical, "│\r\n│")] + [InlineData (0, 0, -2, Orientation.Horizontal, "──")] + [InlineData (1, 0, -2, Orientation.Horizontal, "──")] + [InlineData (0, 1, -2, Orientation.Horizontal, "──")] + [InlineData (0, 0, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (1, 0, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (0, 1, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (1, 1, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (-1, 0, -2, Orientation.Horizontal, "──")] + [InlineData (0, -1, -2, Orientation.Horizontal, "──")] + [InlineData (-1, 0, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (0, -1, -2, Orientation.Vertical, "│\r\n│")] + [InlineData (-1, -1, -2, Orientation.Vertical, "│\r\n│")] + [Theory] public void Length_n_Is_n_Long (int x, int y, int length, Orientation orientation, string expected) + { + var canvas = new LineCanvas (); + canvas.AddLine (new (x, y), length, orientation, LineStyle.Single); + + var result = canvas.ToString (); + OutputAssert.AssertEqual (output, expected, result); + } + + [Fact] + public void Length_Negative () + { + var offset = new Point (5, 5); + + var canvas = new LineCanvas (); + canvas.AddLine (offset, -3, Orientation.Horizontal, LineStyle.Single); + + var looksLike = "───"; + + Assert.Equal (looksLike, $"{canvas}"); + } + + [InlineData (Orientation.Horizontal, "─")] + [InlineData (Orientation.Vertical, "│")] + [Theory] + public void Length_Zero_Alone_Is_Line (Orientation orientation, string expected) + { + var lc = new LineCanvas (); + + // Add a line at 0, 0 that's has length of 0 + lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); + OutputAssert.AssertEqual (output, expected, $"{lc}"); + } + + [InlineData (Orientation.Horizontal, "┼")] + [InlineData (Orientation.Vertical, "┼")] + [Theory] + public void Length_Zero_Cross_Is_Cross (Orientation orientation, string expected) + { + var lc = new LineCanvas (); + + // Add point at opposite orientation + lc.AddLine ( + Point.Empty, + 0, + orientation == Orientation.Horizontal ? Orientation.Vertical : Orientation.Horizontal, + LineStyle.Single + ); + + // Add a line at 0, 0 that's has length of 0 + lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); + OutputAssert.AssertEqual (output, expected, $"{lc}"); + } + + [InlineData (Orientation.Horizontal, "╥")] + [InlineData (Orientation.Vertical, "╞")] + [Theory] + public void Length_Zero_NextTo_Opposite_Is_T (Orientation orientation, string expected) + { + var lc = new LineCanvas (); + + // Add line with length of 1 in opposite orientation starting at same location + if (orientation == Orientation.Horizontal) + { + lc.AddLine (Point.Empty, 1, Orientation.Vertical, LineStyle.Double); + } + else + { + lc.AddLine (Point.Empty, 1, Orientation.Horizontal, LineStyle.Double); + } + + // Add a line at 0, 0 that's has length of 0 + lc.AddLine (Point.Empty, 0, orientation, LineStyle.Single); + OutputAssert.AssertEqual (output, expected, $"{lc}"); + } + + [Fact] + public void TestLineCanvas_LeaveMargin_Top1_Left1 () + { + var canvas = new LineCanvas (); + + // Upper box + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Single); + + var looksLike = + @" +┌─ +│ "; + OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); + } + + [Fact] + public void TestLineCanvas_Window_Heavy () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Heavy); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Heavy); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Heavy); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Heavy); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy); + + v.Draw (); + + var looksLike = + @" +┏━━━━┳━━━┓ +┃ ┃ ┃ +┣━━━━╋━━━┫ +┃ ┃ ┃ +┗━━━━┻━━━┛"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Theory] + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + public void TestLineCanvas_Window_HeavyTop_ThinSides (LineStyle thinStyle) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Heavy); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, thinStyle); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, thinStyle); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, thinStyle); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy); + + v.Draw (); + + var looksLike = + @" +┍━━━━┯━━━┑ +│ │ │ +┝━━━━┿━━━┥ +│ │ │ +┕━━━━┷━━━┙ +"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Theory] + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + public void TestLineCanvas_Window_ThinTop_HeavySides (LineStyle thinStyle) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, thinStyle); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Heavy); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, thinStyle); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Heavy); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Heavy); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, thinStyle); + + v.Draw (); + + var looksLike = + @" +┎────┰───┒ +┃ ┃ ┃ +┠────╂───┨ +┃ ┃ ┃ +┖────┸───┚ + +"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Fact] + public void Top_Left_From_TopRight_LeftUp () + { + var canvas = new LineCanvas (); + + // Upper box + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (new (0, 1), -2, Orientation.Vertical, LineStyle.Single); + + var looksLike = + @" +┌─ +│ "; + OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); + } + + [Fact] + public void Top_With_1Down () + { + var canvas = new LineCanvas (); + + // Top ─ + canvas.AddLine (Point.Empty, 1, Orientation.Horizontal, LineStyle.Single); + + // Bottom ─ + canvas.AddLine (new (1, 1), -1, Orientation.Horizontal, LineStyle.Single); + + //// Right down + //canvas.AddLine (new Point (9, 0), 3, Orientation.Vertical, LineStyle.Single); + + //// Bottom + //canvas.AddLine (new Point (9, 3), -10, Orientation.Horizontal, LineStyle.Single); + + //// Left Up + //canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, LineStyle.Single); + + Assert.Equal (new (0, 0, 2, 2), canvas.Bounds); + + Dictionary map = canvas.GetMap (); + Assert.Equal (2, map.Count); + + OutputAssert.AssertEqual ( + output, + @" +─ + ─", + $"{Environment.NewLine}{canvas}" + ); + } + + [Fact] + public void ToString_Empty () + { + var lc = new LineCanvas (); + OutputAssert.AssertEqual (output, string.Empty, lc.ToString ()); + } + + // 012 + [InlineData (0, 0, "═══")] + [InlineData (1, 0, "═══")] + [InlineData (0, 1, "═══")] + [InlineData (1, 1, "═══")] + [InlineData (2, 2, "═══")] + [InlineData (-1, 0, "═══")] + [InlineData (0, -1, "═══")] + [InlineData (-1, -1, "═══")] + [InlineData (-2, -2, "═══")] + [Theory] + public void ToString_Positive_Horizontal_1Line_Offset (int x, int y, string expected) + { + var lc = new LineCanvas (); + lc.AddLine (new (x, y), 3, Orientation.Horizontal, LineStyle.Double); + OutputAssert.AssertEqual (output, expected, $"{lc}"); + } + + [InlineData (0, 0, 0, 0, "═══")] + [InlineData (1, 0, 1, 0, "═══")] + [InlineData (-1, 0, -1, 0, "═══")] + [InlineData (0, 0, 1, 0, "════")] + [InlineData (1, 0, 3, 0, "═════")] + [InlineData (1, 0, 4, 0, "══════")] + [InlineData (1, 0, 5, 0, "═══ ═══")] + [InlineData (0, 0, 0, 1, "\u2550\u2550\u2550\r\n\u2550\u2550\u2550")] + [InlineData (0, 0, 1, 1, "═══ \r\n ═══")] + [InlineData (0, 0, 2, 1, "═══ \r\n ═══")] + [InlineData (1, 0, 0, 1, " ═══\r\n═══ ")] + [InlineData (0, 1, 0, 1, "═══")] + [InlineData (1, 1, 0, 1, "════")] + [InlineData (2, 2, 0, 1, "═══ \r\n ═══")] + [Theory] + public void ToString_Positive_Horizontal_2Line_Offset (int x1, int y1, int x2, int y2, string expected) + { + var lc = new LineCanvas (); + lc.AddLine (new (x1, y1), 3, Orientation.Horizontal, LineStyle.Double); + lc.AddLine (new (x2, y2), 3, Orientation.Horizontal, LineStyle.Double); + + OutputAssert.AssertEqual (output, expected, $"{lc}"); + } + + // [Fact, SetupFakeDriver] + // public void LeaveMargin_Top1_Left1 () + // { + // var canvas = new LineCanvas (); + + // // Upper box + // canvas.AddLine (Point.Empty, 9, Orientation.Horizontal, LineStyle.Single); + // canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, LineStyle.Single); + // canvas.AddLine (new Point (8, 3), -9, Orientation.Horizontal, LineStyle.Single); + // canvas.AddLine (new Point (0, 2), -3, Orientation.Vertical, LineStyle.Single); + + // // Lower Box + // canvas.AddLine (new Point (5, 0), 2, Orientation.Vertical, LineStyle.Single); + // canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, LineStyle.Single); + + // string looksLike = + //@" + //┌────┬──┐ + //│ │ │ + //├────┼──┤ + //└────┴──┘ + //"; + // Assert.Equal (looksLike, $"{Environment.NewLine}{canvas}"); + // } + + [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Double, "═")] + [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Double, "║")] + [InlineData (0, 0, 0, Orientation.Horizontal, LineStyle.Single, "─")] + [InlineData (0, 0, 0, Orientation.Vertical, LineStyle.Single, "│")] + [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Double, "═")] + [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Double, "║")] + [InlineData (0, 0, 1, Orientation.Horizontal, LineStyle.Single, "─")] + [InlineData (0, 0, 1, Orientation.Vertical, LineStyle.Single, "│")] + [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Double, "══")] + [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Double, "║\n║")] + [InlineData (0, 0, 2, Orientation.Horizontal, LineStyle.Single, "──")] + [InlineData (0, 0, 2, Orientation.Vertical, LineStyle.Single, "│\n│")] + [Theory] + public void View_Draws_1LineTests ( + int x1, + int y1, + int length, + Orientation o1, + LineStyle s1, + string expected + ) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas lc); + v.Width = 10; + v.Height = 10; + v.Viewport = new (0, 0, 10, 10); + + lc.AddLine (new (x1, y1), length, o1, s1); + + v.Draw (); + + DriverAssert.AssertDriverContentsAre (expected, output, driver); + v.Dispose (); + } + + /// This test demonstrates how to correctly trigger a corner. By overlapping the lines in the same cell + [Fact] + public void View_Draws_Corner_Correct () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Single); + + v.Draw (); + + var looksLike = + @" +┌─ +│"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + /// + /// This test demonstrates that corners are only drawn when lines overlap. Not when they terminate adjacent to one + /// another. + /// + [Fact] + public void View_Draws_Corner_NoOverlap () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (new (0, 1), 2, Orientation.Vertical, LineStyle.Single); + + v.Draw (); + + var looksLike = + @" +── +│ +│"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + [Theory] + public void View_Draws_Horizontal (LineStyle style) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, style); + + v.Draw (); + + var looksLike = + @" +──"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Fact] + public void View_Draws_Horizontal_Double () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Horizontal, LineStyle.Double); + + v.Draw (); + + var looksLike = + @" +══"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + [Theory] + public void View_Draws_Vertical (LineStyle style) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Vertical, style); + + v.Draw (); + + var looksLike = + @" +│ +│"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Fact] + + public void View_Draws_Vertical_Double () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + canvas.AddLine (Point.Empty, 2, Orientation.Vertical, LineStyle.Double); + + v.Draw (); + + var looksLike = + @" +║ +║"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Fact] + public void View_Draws_Window_Double () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Double); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Double); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Double); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Double); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Double); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Double); + + v.Draw (); + + var looksLike = + @" +╔════╦═══╗ +║ ║ ║ +╠════╬═══╣ +║ ║ ║ +╚════╩═══╝"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Theory] + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + public void View_Draws_Window_DoubleTop_SingleSides (LineStyle thinStyle) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Double); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, thinStyle); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Double); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, thinStyle); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, thinStyle); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Double); + + v.Draw (); + + var looksLike = + @" +╒════╤═══╕ +│ │ │ +╞════╪═══╡ +│ │ │ +╘════╧═══╛ +"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + /// + /// Demonstrates when corners are used. Notice how not all lines declare rounded. + /// If there are 1+ lines intersecting and a corner is to be used then if any of them are rounded a rounded corner is + /// used. + /// + [Fact] + public void View_Draws_Window_Rounded () + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Rounded); + + // LineStyle.Single is ignored because corner overlaps with the above line which is Rounded + // this results in a rounded corner being used. + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Single); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Single); + + // These lines say rounded but they will result in the T sections which are never rounded. + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Rounded); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Rounded); + + v.Draw (); + + var looksLike = + @" +╭────┬───╮ +│ │ │ +├────┼───┤ +│ │ │ +╰────┴───╯"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Theory] + [InlineData (LineStyle.Single)] + [InlineData (LineStyle.Rounded)] + public void View_Draws_Window_SingleTop_DoubleSides (LineStyle thinStyle) + { + var driver = CreateFakeDriver (); + View v = GetCanvas (driver, out LineCanvas canvas); + + // outer box + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, thinStyle); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Double); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, thinStyle); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Double); + + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Double); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, thinStyle); + + v.Draw (); + + var looksLike = + @" +╓────╥───╖ +║ ║ ║ +╟────╫───╢ +║ ║ ║ +╙────╨───╜ + +"; + DriverAssert.AssertDriverContentsAre (looksLike, output, driver); + v.Dispose (); + } + + [Fact] + public void Window () + { + var canvas = new LineCanvas (); + + // Frame + canvas.AddLine (Point.Empty, 10, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (new (9, 0), 5, Orientation.Vertical, LineStyle.Single); + canvas.AddLine (new (9, 4), -10, Orientation.Horizontal, LineStyle.Single); + canvas.AddLine (new (0, 4), -5, Orientation.Vertical, LineStyle.Single); + + // Cross + canvas.AddLine (new (5, 0), 5, Orientation.Vertical, LineStyle.Single); + canvas.AddLine (new (0, 2), 10, Orientation.Horizontal, LineStyle.Single); + + var looksLike = + @" +┌────┬───┐ +│ │ │ +├────┼───┤ +│ │ │ +└────┴───┘"; + OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{canvas}"); + } + + [Fact] + public void Zero_Length_Intersections () + { + // Draw at 1,2 within client area of View (i.e. leave a top and left margin of 1) + // This proves we aren't drawing excess above + var x = 1; + var y = 2; + var width = 5; + var height = 2; + + var lc = new LineCanvas (); + + // ╔╡╞═════╗ + // Add a short horiz line for ╔╡ + lc.AddLine (new (x, y), 2, Orientation.Horizontal, LineStyle.Double); + + //LHS line down + lc.AddLine (new (x, y), height, Orientation.Vertical, LineStyle.Double); + + //Vertical line before Title, results in a ╡ + lc.AddLine (new (x + 1, y), 0, Orientation.Vertical, LineStyle.Single); + + //Vertical line after Title, results in a ╞ + lc.AddLine (new (x + 2, y), 0, Orientation.Vertical, LineStyle.Single); + + // remainder of top line + lc.AddLine (new (x + 2, y), width - 1, Orientation.Horizontal, LineStyle.Double); + + //RHS line down + lc.AddLine (new (x + width, y), height, Orientation.Vertical, LineStyle.Double); + + var looksLike = @" +╔╡╞══╗ +║ ║"; + OutputAssert.AssertEqual (output, looksLike, $"{Environment.NewLine}{lc}"); + } + + [Fact] + public void LineCanvas_UsesFillCorrectly () + { + // Arrange + var foregroundColor = new Color (255, 0); // Red + var backgroundColor = new Color (0, 0); // Black + var foregroundFill = new SolidFill (foregroundColor); + var backgroundFill = new SolidFill (backgroundColor); + var fillPair = new FillPair (foregroundFill, backgroundFill); + + var lineCanvas = new LineCanvas + { + Fill = fillPair + }; + + // Act + lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); + Dictionary cellMap = lineCanvas.GetCellMap (); + + // Assert + foreach (Cell? cell in cellMap.Values) + { + Assert.NotNull (cell); + Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); + Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); + } + } + + [Fact] + public void LineCanvas_LineColorIgnoredBecauseOfFill () + { + // Arrange + var foregroundColor = new Color (255, 0); // Red + var backgroundColor = new Color (0, 0); // Black + var lineColor = new Attribute (new Color (0, 255), new Color (255, 255, 255)); // Green on White + var foregroundFill = new SolidFill (foregroundColor); + var backgroundFill = new SolidFill (backgroundColor); + var fillPair = new FillPair (foregroundFill, backgroundFill); + + var lineCanvas = new LineCanvas + { + Fill = fillPair + }; + + // Act + lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single, lineColor); + Dictionary cellMap = lineCanvas.GetCellMap (); + + // Assert + foreach (Cell? cell in cellMap.Values) + { + Assert.NotNull (cell); + Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); + Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); + } + } + + [Fact] + public void LineCanvas_IntersectingLinesUseFillCorrectly () + { + // Arrange + var foregroundColor = new Color (255, 0); // Red + var backgroundColor = new Color (0, 0); // Black + var foregroundFill = new SolidFill (foregroundColor); + var backgroundFill = new SolidFill (backgroundColor); + var fillPair = new FillPair (foregroundFill, backgroundFill); + + var lineCanvas = new LineCanvas + { + Fill = fillPair + }; + + // Act + lineCanvas.AddLine (new (0, 0), 5, Orientation.Horizontal, LineStyle.Single); + lineCanvas.AddLine (new (2, -2), 5, Orientation.Vertical, LineStyle.Single); + Dictionary cellMap = lineCanvas.GetCellMap (); + + // Assert + foreach (Cell? cell in cellMap.Values) + { + Assert.NotNull (cell); + Assert.Equal (foregroundColor, cell.Value.Attribute.Value.Foreground); + Assert.Equal (backgroundColor, cell.Value.Attribute.Value.Background); + } + } + + // TODO: Remove this and make all LineCanvas tests independent of View + /// + /// Creates a new into which a is rendered at + /// time. + /// + /// The you can draw into. + /// How far to offset drawing in X + /// How far to offset drawing in Y + /// + private View GetCanvas (IConsoleDriver driver, out LineCanvas canvas, int offsetX = 0, int offsetY = 0) + { + var v = new View { Width = 10, Height = 5, Viewport = new (0, 0, 10, 5) }; + v.Driver = driver; + + LineCanvas canvasCopy = canvas = new (); + + v.DrawComplete += (s, e) => + { + v.FillRect (v.Viewport); + + foreach (KeyValuePair p in canvasCopy.GetMap ()) + { + v.AddRune ( + offsetX + p.Key.X, + offsetY + p.Key.Y, + p.Value + ); + } + + canvasCopy.Clear (); + }; + + return v; + } } diff --git a/Tests/UnitTestsParallelizable/Drawing/RulerTests.cs b/Tests/UnitTestsParallelizable/Drawing/RulerTests.cs index e32bd7e94..5dbb8f032 100644 --- a/Tests/UnitTestsParallelizable/Drawing/RulerTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/RulerTests.cs @@ -1,3 +1,8 @@ +using Microsoft.VisualStudio.TestPlatform.Utilities; +using UnitTests; +using UnitTests.Parallelizable; +using Xunit.Abstractions; + namespace UnitTests_Parallelizable.DrawingTests; /// @@ -6,7 +11,7 @@ namespace UnitTests_Parallelizable.DrawingTests; /// /// Note: Tests that verify rendered output (Draw methods) require Application.Driver and remain in UnitTests as integration tests. /// -public class RulerTests : UnitTests.Parallelizable.ParallelizableBase +public class RulerTests (ITestOutputHelper output): ParallelizableBase { [Fact] public void Constructor_Defaults () @@ -43,4 +48,143 @@ public class RulerTests : UnitTests.Parallelizable.ParallelizableBase r.Orientation = Orientation.Vertical; Assert.Equal (Orientation.Vertical, r.Orientation); } + + [Fact] + public void Draw_Default () + { + IConsoleDriver driver = CreateFakeDriver (); + + var r = new Ruler (); + r.Draw (Point.Empty, driver: driver); + DriverAssert.AssertDriverContentsWithFrameAre (@"", output, driver); + } + + [Fact] + public void Draw_Horizontal () + { + IConsoleDriver driver = CreateFakeDriver (); + + var len = 15; + + var r = new Ruler (); + Assert.Equal (Orientation.Horizontal, r.Orientation); + + r.Length = len; + r.Draw (Point.Empty, driver: driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +|123456789|1234", + output, + driver + ); + + // Postive offset + r.Draw (new (1, 1), driver: driver); + + DriverAssert.AssertDriverContentsAre ( + @" +|123456789|1234 + |123456789|1234 +", + output, + driver + ); + + // Negative offset + r.Draw (new (-1, 3), driver: driver); + + DriverAssert.AssertDriverContentsAre ( + @" +|123456789|1234 + |123456789|1234 +123456789|1234 +", + output, + driver + ); + } + + [Fact] + public void Draw_Vertical () + { + IConsoleDriver driver = CreateFakeDriver (); + + var len = 15; + + var r = new Ruler (); + r.Orientation = Orientation.Vertical; + r.Length = len; + r.Draw (Point.Empty, driver: driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +- +1 +2 +3 +4 +5 +6 +7 +8 +9 +- +1 +2 +3 +4", + output, + driver + ); + + r.Draw (new (1, 1), driver: driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +- +1- +21 +32 +43 +54 +65 +76 +87 +98 +-9 +1- +21 +32 +43 + 4", + output, + driver + ); + + // Negative offset + r.Draw (new (2, -1), driver: driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +- 1 +1-2 +213 +324 +435 +546 +657 +768 +879 +98- +-91 +1-2 +213 +324 +43 + 4 ", + output, + driver + ); + } } diff --git a/Tests/UnitTests/Drawing/StraightLineExtensionsTests.cs b/Tests/UnitTestsParallelizable/Drawing/StraightLineExtensionsTests.cs similarity index 97% rename from Tests/UnitTests/Drawing/StraightLineExtensionsTests.cs rename to Tests/UnitTestsParallelizable/Drawing/StraightLineExtensionsTests.cs index 0573fec7e..47aedbcef 100644 --- a/Tests/UnitTests/Drawing/StraightLineExtensionsTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/StraightLineExtensionsTests.cs @@ -1,12 +1,10 @@ -using UnitTests; -using Xunit.Abstractions; +using Xunit.Abstractions; namespace UnitTests.DrawingTests; public class StraightLineExtensionsTests (ITestOutputHelper output) { [Fact] - [AutoInitShutdown] public void LineCanvasIntegrationTest () { var lc = new LineCanvas (); @@ -146,7 +144,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) #region Parallel Tests [Fact] - [AutoInitShutdown] public void TestExcludeParallel_HorizontalLines_LeftOnly () { // x=1 to x=10 @@ -165,7 +162,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_HorizontalLines_RightOnly () { // x=1 to x=10 @@ -185,7 +181,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_HorizontalLines_HorizontalSplit () { // x=1 to x=10 @@ -213,7 +208,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_HorizontalLines_CoverCompletely () { // x=1 to x=10 @@ -228,7 +222,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_VerticalLines_TopOnly () { // y=1 to y=10 @@ -247,7 +240,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_HorizontalLines_BottomOnly () { // y=1 to y=10 @@ -267,7 +259,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_VerticalLines_VerticalSplit () { // y=1 to y=10 @@ -295,7 +286,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludeParallel_VerticalLines_CoverCompletely () { // y=1 to y=10 @@ -314,7 +304,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) #region Perpendicular Intersection Tests [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_HorizontalLine_VerticalExclusion_Splits () { // x=1 to x=10 @@ -342,7 +331,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_HorizontalLine_VerticalExclusion_ClipLeft () { // x=1 to x=10 @@ -363,7 +351,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_HorizontalLine_VerticalExclusion_ClipRight () { // x=1 to x=10 @@ -384,7 +371,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_HorizontalLine_VerticalExclusion_MissLeft () { // x=1 to x=10 @@ -401,7 +387,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_HorizontalLine_VerticalExclusion_MissRight () { // x=1 to x=10 @@ -418,7 +403,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_VerticalLine_HorizontalExclusion_ClipTop () { // y=1 to y=10 @@ -439,7 +423,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_VerticalLine_HorizontalExclusion_ClipBottom () { // y=1 to y=10 @@ -460,7 +443,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_VerticalLine_HorizontalExclusion_MissTop () { // y=1 to y=10 @@ -477,7 +459,6 @@ public class StraightLineExtensionsTests (ITestOutputHelper output) } [Fact] - [AutoInitShutdown] public void TestExcludePerpendicular_VerticalLine_HorizontalExclusion_MissBottom () { // y=1 to y=10 diff --git a/Tests/UnitTestsParallelizable/Drawing/ThicknessTests.cs b/Tests/UnitTestsParallelizable/Drawing/ThicknessTests.cs index d09d66f2c..333e58400 100644 --- a/Tests/UnitTestsParallelizable/Drawing/ThicknessTests.cs +++ b/Tests/UnitTestsParallelizable/Drawing/ThicknessTests.cs @@ -1,6 +1,11 @@ -namespace UnitTests_Parallelizable.DrawingTests; +using System.Text; +using UnitTests; +using UnitTests.Parallelizable; +using Xunit.Abstractions; -public class ThicknessTests +namespace UnitTests_Parallelizable.DrawingTests; + +public class ThicknessTests (ITestOutputHelper output) : ParallelizableBase { [Fact] public void Constructor_Defaults () @@ -616,4 +621,263 @@ public class ThicknessTests Assert.Equal (expectedRight, result.Right); Assert.Equal (expectedBottom, result.Bottom); } + + [Fact] + public void DrawTests () + { + IConsoleDriver driver = new FakeDriver (); + driver.SetScreenSize (60, 40); + + var t = new Thickness (0, 0, 0, 0); + var r = new Rectangle (5, 5, 40, 15); + + driver.FillRect ( + new (0, 0, driver!.Cols, driver!.Rows), + (Rune)' ' + ); + t.Draw (r, ViewDiagnosticFlags.Thickness, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" + Test (Left=0,Top=0,Right=0,Bottom=0)", + output, + driver + ); + + t = new (1, 1, 1, 1); + r = new (5, 5, 40, 15); + + driver.FillRect ( + new (0, 0, driver!.Cols, driver!.Rows), + (Rune)' ' + ); + t.Draw (r, ViewDiagnosticFlags.Thickness, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + T T + T T + T T + T T + T T + T T + T T + T T + T T + T T + T T + T T + T T + TTTest (Left=1,Top=1,Right=1,Bottom=1)TT", + output, + driver + ); + + t = new (1, 2, 3, 4); + r = new (5, 5, 40, 15); + + driver?.FillRect ( + new (0, 0, driver!.Cols, driver!.Rows), + (Rune)' ' + ); + t.Draw (r, ViewDiagnosticFlags.Thickness, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + T TTT + T TTT + T TTT + T TTT + T TTT + T TTT + T TTT + T TTT + T TTT + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + TTTest (Left=1,Top=2,Right=3,Bottom=4)TT", + output, + driver + ); + + t = new (-1, 1, 1, 1); + r = new (5, 5, 40, 15); + + driver?.FillRect ( + new (0, 0, driver!.Cols, driver!.Rows), + (Rune)' ' + ); + t.Draw (r, ViewDiagnosticFlags.Thickness, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" + TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + T + T + T + T + T + T + T + T + T + T + T + T + T + TTest (Left=-1,Top=1,Right=1,Bottom=1)TT", + output, + driver + ); + } + + [Fact] + public void DrawTests_Ruler () + { + IConsoleDriver driver = new FakeDriver (); + + // Add a frame so we can see the ruler + var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single }; + f.Driver = driver; + driver.SetScreenSize (45, 20); + + var top = new Toplevel () { Width = driver.Cols, Height = driver.Rows }; + top.Driver = driver; + top.Add (f); + + top.Layout (); + + var t = new Thickness (0, 0, 0, 0); + var r = new Rectangle (2, 2, 40, 15); + + top.Draw (); + t.Draw (r, ViewDiagnosticFlags.Ruler, "Test", driver); + + DriverAssert.AssertDriverContentsAre ( + @" +┌───────────────────────────────────────────┐ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└───────────────────────────────────────────┘", + output, + driver + ); + + t = new (1, 1, 1, 1); + r = new (1, 1, 40, 15); + top.SetNeedsDraw (); + top.Draw (); + t.Draw (r, ViewDiagnosticFlags.Ruler, "Test", driver); + + DriverAssert.AssertDriverContentsAre ( + @" +┌───────────────────────────────────────────┐ +│|123456789|123456789|123456789|123456789 │ +│1 1 │ +│2 2 │ +│3 3 │ +│4 4 │ +│5 5 │ +│6 6 │ +│7 7 │ +│8 8 │ +│9 9 │ +│- - │ +│1 1 │ +│2 2 │ +│3 3 │ +│|123456789|123456789|123456789|123456789 │ +│ │ +│ │ +│ │ +└───────────────────────────────────────────┘", + output, + driver + ); + + t = new (1, 2, 3, 4); + r = new (2, 2, 40, 15); + top.SetNeedsDraw (); + top.Draw (); + t.Draw (r, ViewDiagnosticFlags.Ruler, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +┌───────────────────────────────────────────┐ +│ │ +│ |123456789|123456789|123456789|123456789 │ +│ 1 1 │ +│ 2 2 │ +│ 3 3 │ +│ 4 4 │ +│ 5 5 │ +│ 6 6 │ +│ 7 7 │ +│ 8 8 │ +│ 9 9 │ +│ - - │ +│ 1 1 │ +│ 2 2 │ +│ 3 3 │ +│ |123456789|123456789|123456789|123456789 │ +│ │ +│ │ +└───────────────────────────────────────────┘", + output, + driver + ); + + t = new (-1, 1, 1, 1); + r = new (5, 5, 40, 15); + top.SetNeedsDraw (); + top.Draw (); + t.Draw (r, ViewDiagnosticFlags.Ruler, "Test", driver); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +┌───────────────────────────────────────────┐ +│ │ +│ │ +│ │ +│ │ +│ |123456789|123456789|123456789|123456789 +│ 1 +│ 2 +│ 3 +│ 4 +│ 5 +│ 6 +│ 7 +│ 8 +│ 9 +│ - +│ 1 +│ 2 +│ 3 +└────|123456789|123456789|123456789|123456789", + output, + driver + ); + top.Dispose (); + } } diff --git a/Tests/UnitTestsParallelizable/Input/Keyboard/KeyTests.cs b/Tests/UnitTestsParallelizable/Input/Keyboard/KeyTests.cs index 778fbf11b..12e5044fb 100644 --- a/Tests/UnitTestsParallelizable/Input/Keyboard/KeyTests.cs +++ b/Tests/UnitTestsParallelizable/Input/Keyboard/KeyTests.cs @@ -573,4 +573,22 @@ public class KeyTests Key b = Key.A; Assert.False (a.Equals (b)); } + + + [Fact] + public void KeyPressed_Handled_True_Cancels_KeyPress () + { + var r = new View (); + var args = new Key { KeyCode = KeyCode.Null }; + + Assert.False (r.NewKeyDownEvent (args)); + Assert.False (args.Handled); + + r.KeyDown += (s, a) => a.Handled = true; + Assert.True (r.NewKeyDownEvent (args)); + Assert.True (args.Handled); + + r.Dispose (); + } + } diff --git a/Tests/UnitTestsParallelizable/Input/ResponderTests.cs b/Tests/UnitTestsParallelizable/Input/ResponderTests.cs deleted file mode 100644 index 94c4a00e5..000000000 --- a/Tests/UnitTestsParallelizable/Input/ResponderTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Alias Console to MockConsole so we don't accidentally use Console - -namespace UnitTests_Parallelizable.InputTests; - -public class ResponderTests -{ - [Fact] - public void KeyPressed_Handled_True_Cancels_KeyPress () - { - var r = new View (); - var args = new Key { KeyCode = KeyCode.Null }; - - Assert.False (r.NewKeyDownEvent (args)); - Assert.False (args.Handled); - - r.KeyDown += (s, a) => a.Handled = true; - Assert.True (r.NewKeyDownEvent (args)); - Assert.True (args.Handled); - - r.Dispose (); - } - - public class DerivedView : View - { - protected override bool OnKeyDown (Key keyEvent) { return true; } - } -} diff --git a/Tests/UnitTestsParallelizable/MockConsoleDriver.cs b/Tests/UnitTestsParallelizable/MockConsoleDriver.cs deleted file mode 100644 index 50f025834..000000000 --- a/Tests/UnitTestsParallelizable/MockConsoleDriver.cs +++ /dev/null @@ -1,203 +0,0 @@ -#nullable enable -using System.Text; - - -internal class MockConsoleDriver : IConsoleDriver -{ - public event EventHandler? AttributeSet; - - private IClipboard? _clipboard; - private Rectangle _screen; - private Region? _clip; - private int _col; - private int _cols; - private Cell [,]? _contents; - private int _left; - private int _row; - private int _rows; - private int _top; - private bool _supportsTrueColor; - private bool _force16Colors; - private Attribute _currentAttribute; - - /// - public IClipboard? Clipboard => _clipboard; - - /// - public Rectangle Screen => _screen; - - /// - public Region? Clip - { - get => _clip; - set => _clip = value; - } - - /// - public int Col => _col; - - /// - public int Cols - { - get => _cols; - set => _cols = value; - } - - /// - public Cell [,]? Contents - { - get => _contents; - set => _contents = value; - } - - /// - public int Left - { - get => _left; - set => _left = value; - } - - /// - public int Row => _row; - - /// - public int Rows - { - get => _rows; - set => _rows = value; - } - - /// - public int Top - { - get => _top; - set => _top = value; - } - - /// - public bool SupportsTrueColor => _supportsTrueColor; - - /// - public bool Force16Colors - { - get => _force16Colors; - set => _force16Colors = value; - } - - /// - public Attribute CurrentAttribute - { - get => _currentAttribute; - set => _currentAttribute = value; - } - - /// - public string GetVersionInfo () { return string.Empty; } - - /// - public void WriteRaw (string ansi) { } - - /// - public bool IsRuneSupported (Rune rune) { return true; } - - /// - public bool IsValidLocation (Rune rune, int col, int row) { return true; } - - /// - public void Move (int col, int row) - { - _col = col; - _row = row; - } - - /// - public void AddRune (Rune rune) { } - - /// - public void AddRune (char c) { } - - /// - public void AddStr (string str) { } - - /// - public void ClearContents () { } - - /// - public event EventHandler? ClearedContents; - - /// - public void FillRect (Rectangle rect, Rune rune = default) { } - - /// - public void FillRect (Rectangle rect, char c) { } - - /// - public bool GetCursorVisibility (out CursorVisibility visibility) - { - visibility = CursorVisibility.Invisible; - return false; - - } - - /// - public void Refresh () { } - - /// - public bool SetCursorVisibility (CursorVisibility visibility) { throw new NotImplementedException (); } - - /// - public event EventHandler? SizeChanged; - - /// - public void Suspend () { } - - /// - public void UpdateCursor () {} - - /// - public void Init () { } - - /// - public void End () { } - - /// - - /// - public Attribute SetAttribute (Attribute c) - { - Attribute oldAttribute = _currentAttribute; - _currentAttribute = c; - - AttributeSet?.Invoke (this, c); - - return oldAttribute; - } - - /// - public Attribute GetAttribute () - { - return _currentAttribute; - } - - - /// - public Attribute MakeColor (in Color foreground, in Color background) { throw new NotImplementedException (); } - - /// - public event EventHandler? MouseEvent; - - /// - public event EventHandler? KeyDown; - - /// - public event EventHandler? KeyUp; - - /// - public void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl) { throw new NotImplementedException (); } - - /// - public void QueueAnsiRequest (AnsiEscapeSequenceRequest request) { throw new NotImplementedException (); } - - /// - public AnsiRequestScheduler GetRequestScheduler () { throw new NotImplementedException (); } -} diff --git a/Tests/UnitTestsParallelizable/ParallelizableBase.cs b/Tests/UnitTestsParallelizable/ParallelizableBase.cs index 29fb4ae01..55b038472 100644 --- a/Tests/UnitTestsParallelizable/ParallelizableBase.cs +++ b/Tests/UnitTestsParallelizable/ParallelizableBase.cs @@ -20,11 +20,10 @@ public abstract class ParallelizableBase /// Width of the driver buffer /// Height of the driver buffer /// A configured IFakeConsoleDriver instance - protected static IFakeConsoleDriver CreateFakeDriver (int width = 25, int height = 25) + protected static IConsoleDriver CreateFakeDriver (int width = 25, int height = 25) { - var factory = new FakeDriverFactory (); - IFakeConsoleDriver driver = factory.Create (); - driver.SetBufferSize (width, height); + IConsoleDriver driver = new FakeDriver (); + driver.SetScreenSize (width, height); return driver; } } diff --git a/Tests/UnitTestsParallelizable/UnitTests.Parallelizable.csproj b/Tests/UnitTestsParallelizable/UnitTests.Parallelizable.csproj index 284585831..50e7e234a 100644 --- a/Tests/UnitTestsParallelizable/UnitTests.Parallelizable.csproj +++ b/Tests/UnitTestsParallelizable/UnitTests.Parallelizable.csproj @@ -31,6 +31,7 @@ + diff --git a/Tests/UnitTestsParallelizable/View/Adornment/AdornmentTests.cs b/Tests/UnitTestsParallelizable/View/Adornment/AdornmentTests.cs index 62b371df1..bbaad3a2b 100644 --- a/Tests/UnitTestsParallelizable/View/Adornment/AdornmentTests.cs +++ b/Tests/UnitTestsParallelizable/View/Adornment/AdornmentTests.cs @@ -76,20 +76,20 @@ public class AdornmentTests Assert.Equal (new (0, 0, 20, 20), view.Viewport); var marginThickness = 1; - view.Margin.Thickness = new (marginThickness); + view.Margin!.Thickness = new (marginThickness); Assert.Equal (new (0, 0, 18, 18), view.Viewport); var borderThickness = 2; - view.Border.Thickness = new (borderThickness); + view.Border!.Thickness = new (borderThickness); Assert.Equal (new (0, 0, 14, 14), view.Viewport); var paddingThickness = 3; - view.Padding.Thickness = new (paddingThickness); + view.Padding!.Thickness = new (paddingThickness); Assert.Equal (new (0, 0, 8, 8), view.Viewport); - Assert.Equal (new (0, 0, view.Margin.Frame.Width, view.Margin.Frame.Height), view.Margin.Viewport); + Assert.Equal (new (0, 0, view.Margin!.Frame.Width, view.Margin!.Frame.Height), view.Margin!.Viewport); - Assert.Equal (new (0, 0, view.Border.Frame.Width, view.Border.Frame.Height), view.Border.Viewport); + Assert.Equal (new (0, 0, view.Border!.Frame.Width, view.Border!.Frame.Height), view.Border!.Viewport); Assert.Equal (new (0, 0, view.Padding.Frame.Width, view.Padding.Frame.Height), view.Padding.Viewport); } @@ -131,7 +131,7 @@ public class AdornmentTests [InlineData (1, 1, 1, 0, 4)] public void Viewport_Width_Is_Frame_Width (int thickness, int x, int y, int w, int h) { - var adornment = new Adornment (null); + var adornment = new Adornment (null!); adornment.Thickness = new (thickness); adornment.Frame = new (x, y, w, h); Assert.Equal (new (x, y, w, h), adornment.Frame); @@ -151,11 +151,11 @@ public class AdornmentTests Assert.Equal (new (1, 2, 10, 10), parent.Frame); Assert.Equal (new (0, 0, 10, 10), parent.Viewport); - Assert.Equal (new (0, 0, 10, 10), parent.Margin.Frame); - Assert.Equal (new (0, 0, 10, 10), parent.Margin.Viewport); + Assert.Equal (new (0, 0, 10, 10), parent.Margin!.Frame); + Assert.Equal (new (0, 0, 10, 10), parent.Margin!.Viewport); - Assert.Null (parent.Margin.SuperView); - Rectangle boundsAsScreen = parent.Margin.ViewportToScreen (new Rectangle (1, 2, 5, 5)); + Assert.Null (parent.Margin!.SuperView); + Rectangle boundsAsScreen = parent.Margin!.ViewportToScreen (new Rectangle (1, 2, 5, 5)); Assert.Equal (new (2, 4, 5, 5), boundsAsScreen); } @@ -167,8 +167,8 @@ public class AdornmentTests Assert.Equal (new (1, 2, 10, 20), parent.Frame); Assert.Equal (new (0, 0, 10, 20), parent.Viewport); - Assert.Equal (new (0, 0, 10, 20), parent.Margin.Frame); - Assert.Equal (new (0, 0, 10, 20), parent.Margin.Viewport); + Assert.Equal (new (0, 0, 10, 20), parent.Margin!.Frame); + Assert.Equal (new (0, 0, 10, 20), parent.Margin!.Viewport); } [Fact] @@ -183,13 +183,13 @@ public class AdornmentTests }; var marginThickness = 1; - view.Margin.Thickness = new (marginThickness); + view.Margin!.Thickness = new (marginThickness); var borderThickness = 2; - view.Border.Thickness = new (borderThickness); + view.Border!.Thickness = new (borderThickness); var paddingThickness = 3; - view.Padding.Thickness = new (paddingThickness); + view.Padding!.Thickness = new (paddingThickness); view.BeginInit (); view.EndInit (); @@ -198,12 +198,12 @@ public class AdornmentTests Assert.Equal (new (0, 0, 8, 19), view.Viewport); // Margin.Frame is always the same as the view frame - Assert.Equal (new (0, 0, 20, 31), view.Margin.Frame); + Assert.Equal (new (0, 0, 20, 31), view.Margin!.Frame); // Border.Frame is View.Frame minus the Margin thickness Assert.Equal ( new (marginThickness, marginThickness, view.Frame.Width - marginThickness * 2, view.Frame.Height - marginThickness * 2), - view.Border.Frame); + view.Border!.Frame); // Padding.Frame is View.Frame minus the Border thickness plus Margin thickness Assert.Equal ( @@ -226,15 +226,15 @@ public class AdornmentTests public void FrameToScreen_Retains_Frame_Size (int marginThickness, int w, int h) { var parent = new View { X = 1, Y = 2, Width = w, Height = h }; - parent.Margin.Thickness = new (marginThickness); + parent.Margin!.Thickness = new (marginThickness); parent.BeginInit (); parent.EndInit (); Assert.Equal (new (1, 2, w, h), parent.Frame); - Assert.Equal (new (0, 0, w, h), parent.Margin.Frame); + Assert.Equal (new (0, 0, w, h), parent.Margin!.Frame); - Assert.Equal (parent.Frame, parent.Margin.FrameToScreen ()); + Assert.Equal (parent.Frame, parent.Margin!.FrameToScreen ()); } // Test that Adornment.FrameToScreen override returns Frame if Parent is null @@ -276,8 +276,8 @@ public class AdornmentTests Width = 20, Height = 20 }; - superView.Margin.Thickness = new (marginThickness); - superView.Border.Thickness = new (borderThickness); + superView.Margin!.Thickness = new (marginThickness); + superView.Border!.Thickness = new (borderThickness); var view = new View { X = x, Y = y, Width = 1, Height = 1 }; superView.Add (view); @@ -285,16 +285,16 @@ public class AdornmentTests superView.EndInit (); Assert.Equal (new (x, y, 1, 1), view.Frame); - Assert.Equal (new (0, 0, 20, 20), superView.Margin.Frame); + Assert.Equal (new (0, 0, 20, 20), superView.Margin!.Frame); Assert.Equal ( new (marginThickness, marginThickness, 20 - marginThickness * 2, 20 - marginThickness * 2), - superView.Border.Frame + superView.Border!.Frame ); Assert.Equal ( new (superView.Frame.X + marginThickness, superView.Frame.Y + marginThickness, 20 - marginThickness * 2, 20 - marginThickness * 2), - superView.Border.FrameToScreen () + superView.Border!.FrameToScreen () ); } @@ -309,11 +309,11 @@ public class AdornmentTests Assert.Equal (new (1, 2, 10, 10), parent.Frame); Assert.Equal (new (0, 0, 10, 10), parent.Viewport); - Assert.Equal (new (0, 0, 10, 10), parent.Margin.Frame); - Assert.Equal (new (0, 0, 10, 10), parent.Margin.Viewport); + Assert.Equal (new (0, 0, 10, 10), parent.Margin!.Frame); + Assert.Equal (new (0, 0, 10, 10), parent.Margin!.Viewport); - Assert.Null (parent.Margin.SuperView); - Assert.Equal (new (1, 2, 10, 10), parent.Margin.FrameToScreen ()); + Assert.Null (parent.Margin!.SuperView); + Assert.Equal (new (1, 2, 10, 10), parent.Margin!.FrameToScreen ()); } [Fact] @@ -322,13 +322,13 @@ public class AdornmentTests var view = new View (); Assert.Equal (Thickness.Empty, view.GetAdornmentsThickness ()); - view.Margin.Thickness = new (1); + view.Margin!.Thickness = new (1); Assert.Equal (new (1), view.GetAdornmentsThickness ()); - view.Border.Thickness = new (1); + view.Border!.Thickness = new (1); Assert.Equal (new (2), view.GetAdornmentsThickness ()); - view.Padding.Thickness = new (1); + view.Padding!.Thickness = new (1); Assert.Equal (new (3), view.GetAdornmentsThickness ()); view.Padding.Thickness = new (2); @@ -337,7 +337,7 @@ public class AdornmentTests view.Padding.Thickness = new (1, 2, 3, 4); Assert.Equal (new (3, 4, 5, 6), view.GetAdornmentsThickness ()); - view.Margin.Thickness = new (1, 2, 3, 4); + view.Margin!.Thickness = new (1, 2, 3, 4); Assert.Equal (new (3, 5, 7, 9), view.GetAdornmentsThickness ()); view.Dispose (); } @@ -345,14 +345,14 @@ public class AdornmentTests [Fact] public void Setting_Viewport_Throws () { - var adornment = new Adornment (null); + var adornment = new Adornment (null!); Assert.Throws (() => adornment.Viewport = new (1, 2, 3, 4)); } [Fact] public void Setting_SuperViewRendersLineCanvas_Throws () { - var adornment = new Adornment (null); + var adornment = new Adornment (null!); Assert.Throws (() => adornment.SuperViewRendersLineCanvas = true); } @@ -366,7 +366,7 @@ public class AdornmentTests Assert.Equal (new (0, 0, 10, 10), parent.Frame); Assert.Equal (new (0, 0, 10, 10), parent.Viewport); - parent.Margin.Thickness = new (1); + parent.Margin!.Thickness = new (1); Assert.Equal (new (0, 0, 10, 10), parent.Frame); Assert.Equal (new (0, 0, 8, 8), parent.Viewport); } @@ -374,7 +374,7 @@ public class AdornmentTests [Fact] public void Setting_Thickness_Raises_ThicknessChanged () { - var adornment = new Adornment (null); + var adornment = new Adornment (null!); var super = new View (); var raised = false; @@ -396,15 +396,15 @@ public class AdornmentTests parent.EndInit (); parent.SubViewLayout += LayoutStarted; - parent.Margin.Thickness = new (1, 2, 3, 4); + parent.Margin!.Thickness = new (1, 2, 3, 4); Assert.True (parent.NeedsLayout); - Assert.True (parent.Margin.NeedsLayout); + Assert.True (parent.Margin!.NeedsLayout); parent.Layout (); Assert.True (raised); return; - void LayoutStarted (object sender, LayoutEventArgs e) { raised = true; } + void LayoutStarted (object? sender, LayoutEventArgs e) { raised = true; } } [Fact] @@ -415,16 +415,16 @@ public class AdornmentTests parent.BeginInit (); parent.EndInit (); - parent.Margin.SubViewLayout += LayoutStarted; - parent.Margin.Thickness = new (1, 2, 3, 4); + parent.Margin!.SubViewLayout += LayoutStarted; + parent.Margin!.Thickness = new (1, 2, 3, 4); Assert.True (parent.NeedsLayout); - Assert.True (parent.Margin.NeedsLayout); + Assert.True (parent.Margin!.NeedsLayout); parent.Layout (); Assert.True (raised); return; - void LayoutStarted (object sender, LayoutEventArgs e) { raised = true; } + void LayoutStarted (object? sender, LayoutEventArgs e) { raised = true; } } [Fact] @@ -434,7 +434,7 @@ public class AdornmentTests view.BeginInit (); view.EndInit (); - view.Padding.Thickness = new (2, 2, 2, 2); + view.Padding!.Thickness = new (2, 2, 2, 2); Assert.Throws (() => view.Padding.Viewport = view.Padding.Viewport with { Location = new (1, 1) }); } diff --git a/Tests/UnitTestsParallelizable/View/Adornment/MarginTests.cs b/Tests/UnitTestsParallelizable/View/Adornment/MarginTests.cs index 6719c0ee5..d7cc2ed0d 100644 --- a/Tests/UnitTestsParallelizable/View/Adornment/MarginTests.cs +++ b/Tests/UnitTestsParallelizable/View/Adornment/MarginTests.cs @@ -28,7 +28,7 @@ public class MarginTests view.Margin!.Thickness = new Thickness (1, 1, 1, 1); // Give it Text - view.Margin.Text = "Test"; + view.Margin!.Text = "Test"; // Strip off ViewportSettings.Transparent view.Margin!.ViewportSettings &= ~ViewportSettingsFlags.Transparent; @@ -50,7 +50,7 @@ public class MarginTests { var view = new View { Height = 3, Width = 3, ShadowStyle = ShadowStyle.Transparent }; Assert.Equal (ShadowStyle.Transparent, view.Margin!.ShadowStyle); - Assert.True (view.Margin.ViewportSettings.HasFlag (ViewportSettingsFlags.TransparentMouse), "Margin should be transparent to mouse when ShadowStyle is Transparent."); + Assert.True (view.Margin!.ViewportSettings.HasFlag (ViewportSettingsFlags.TransparentMouse), "Margin should be transparent to mouse when ShadowStyle is Transparent."); Assert.True (view.Margin!.ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent), "Margin should be transparent when ShadowStyle is Transparent.."); } @@ -59,7 +59,7 @@ public class MarginTests { var view = new View { Height = 3, Width = 3, ShadowStyle = ShadowStyle.Opaque }; Assert.Equal (ShadowStyle.Opaque, view.Margin!.ShadowStyle); - Assert.True (view.Margin.ViewportSettings.HasFlag (ViewportSettingsFlags.TransparentMouse), "Margin should be transparent to mouse when ShadowStyle is Opaque."); + Assert.True (view.Margin!.ViewportSettings.HasFlag (ViewportSettingsFlags.TransparentMouse), "Margin should be transparent to mouse when ShadowStyle is Opaque."); Assert.True (view.Margin!.ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent), "Margin should be transparent when ShadowStyle is Opaque.."); } diff --git a/Tests/UnitTestsParallelizable/View/Layout/GetViewsUnderLocationTests.cs b/Tests/UnitTestsParallelizable/View/Layout/GetViewsUnderLocationTests.cs index 7e8a93564..4bb0506c1 100644 --- a/Tests/UnitTestsParallelizable/View/Layout/GetViewsUnderLocationTests.cs +++ b/Tests/UnitTestsParallelizable/View/Layout/GetViewsUnderLocationTests.cs @@ -128,14 +128,14 @@ public class GetViewsUnderLocationTests containedType = view.GetType (); } - if (view.Margin.Contains (new (testX, testY))) + if (view.Margin!.Contains (new (testX, testY))) { - containedType = view.Margin.GetType (); + containedType = view.Margin!.GetType (); } - if (view.Border.Contains (new (testX, testY))) + if (view.Border!.Contains (new (testX, testY))) { - containedType = view.Border.GetType (); + containedType = view.Border!.GetType (); } if (view.Padding.Contains (new (testX, testY))) diff --git a/Tests/UnitTestsParallelizable/View/Layout/LayoutTests.cs b/Tests/UnitTestsParallelizable/View/Layout/LayoutTests.cs index 27b34c2b9..1c45576f2 100644 --- a/Tests/UnitTestsParallelizable/View/Layout/LayoutTests.cs +++ b/Tests/UnitTestsParallelizable/View/Layout/LayoutTests.cs @@ -275,8 +275,8 @@ public class LayoutTests : GlobalTestSetup view.SubViewLayout += (sender, e) => layoutStartedCount++; view.SubViewsLaidOut += (sender, e) => layoutCompleteCount++; - view.Border.SubViewLayout += (sender, e) => borderLayoutStartedCount++; - view.Border.SubViewsLaidOut += (sender, e) => borderLayoutCompleteCount++; + view.Border!.SubViewLayout += (sender, e) => borderLayoutStartedCount++; + view.Border!.SubViewsLaidOut += (sender, e) => borderLayoutCompleteCount++; superView.Add (view); @@ -300,7 +300,7 @@ public class LayoutTests : GlobalTestSetup Assert.Equal (2, layoutCompleteCount); // With Border subview - view.Border.Add (new View ()); + view.Border!.Add (new View ()); superView.LayoutSubViews (); Assert.Equal (1, borderLayoutStartedCount); Assert.Equal (1, borderLayoutCompleteCount); @@ -338,8 +338,8 @@ public class LayoutTests : GlobalTestSetup view.SubViewLayout += (sender, e) => layoutStartedCount++; view.SubViewsLaidOut += (sender, e) => layoutCompleteCount++; - view.Border.SubViewLayout += (sender, e) => borderLayoutStartedCount++; - view.Border.SubViewsLaidOut += (sender, e) => borderLayoutCompleteCount++; + view.Border!.SubViewLayout += (sender, e) => borderLayoutStartedCount++; + view.Border!.SubViewsLaidOut += (sender, e) => borderLayoutCompleteCount++; superView.Add (view); Assert.Equal (0, borderLayoutStartedCount); diff --git a/Tests/UnitTestsParallelizable/View/Layout/ToScreenTests.cs b/Tests/UnitTestsParallelizable/View/Layout/ToScreenTests.cs index 1c2a12989..e005b7ca9 100644 --- a/Tests/UnitTestsParallelizable/View/Layout/ToScreenTests.cs +++ b/Tests/UnitTestsParallelizable/View/Layout/ToScreenTests.cs @@ -119,7 +119,7 @@ public class ToScreenTests () Height = 1 }; - view.Border.Add (subviewOfBorder); + view.Border!.Add (subviewOfBorder); view.BeginInit (); view.EndInit (); diff --git a/Tests/UnitTestsParallelizable/View/Layout/ViewportTests.cs b/Tests/UnitTestsParallelizable/View/Layout/ViewportTests.cs index 11c935283..123ff90c2 100644 --- a/Tests/UnitTestsParallelizable/View/Layout/ViewportTests.cs +++ b/Tests/UnitTestsParallelizable/View/Layout/ViewportTests.cs @@ -55,7 +55,7 @@ public class ViewportTests (ITestOutputHelper output) Height = 10, Width = 10, }; - superSuperView.Border.Thickness = new Thickness (borderThickness); + superSuperView.Border!.Thickness = new Thickness (borderThickness); var superView = new View () { @@ -64,7 +64,7 @@ public class ViewportTests (ITestOutputHelper output) Height = Dim.Fill (), Width = Dim.Fill () }; - superView.Border.Thickness = new Thickness (borderThickness); + superView.Border!.Thickness = new Thickness (borderThickness); superSuperView.Add (superView); @@ -113,7 +113,7 @@ public class ViewportTests (ITestOutputHelper output) Height = 10, Width = 10, }; - superSuperView.Border.Thickness = new Thickness (borderThickness); + superSuperView.Border!.Thickness = new Thickness (borderThickness); var superView = new View () { @@ -122,7 +122,7 @@ public class ViewportTests (ITestOutputHelper output) Height = Dim.Fill (), Width = Dim.Fill () }; - superView.Border.Thickness = new Thickness (borderThickness); + superView.Border!.Thickness = new Thickness (borderThickness); superSuperView.Add (superView); @@ -133,7 +133,7 @@ public class ViewportTests (ITestOutputHelper output) Height = Dim.Fill (), Width = Dim.Fill () }; - view.Border.Thickness = new Thickness (borderThickness); + view.Border!.Thickness = new Thickness (borderThickness); superView.Add (view); superSuperView.BeginInit (); @@ -328,7 +328,7 @@ public class ViewportTests (ITestOutputHelper output) }; view.BeginInit (); view.EndInit (); - view.Margin.Thickness = new (adornmentThickness); + view.Margin!.Thickness = new (adornmentThickness); Assert.Equal (expectedOffset, view.GetViewportOffsetFromFrame ().X); } diff --git a/Tests/UnitTestsParallelizable/View/Navigation/SetFocusTests.cs b/Tests/UnitTestsParallelizable/View/Navigation/SetFocusTests.cs index 09dc7edb4..1eb8c6383 100644 --- a/Tests/UnitTestsParallelizable/View/Navigation/SetFocusTests.cs +++ b/Tests/UnitTestsParallelizable/View/Navigation/SetFocusTests.cs @@ -236,14 +236,14 @@ public class SetFocusTests () : TestsAllViews }; borderSubView.Add (subViewSubView1, subViewSubView2, subViewSubView3); - view.Border.Add (borderSubView); + view.Border!.Add (borderSubView); view.SetFocus (); Assert.True (view.HasFocus); Assert.True (subView.HasFocus); Assert.False (borderSubView.HasFocus); - view.Border.CanFocus = true; + view.Border!.CanFocus = true; subViewSubView1.SetFocus (); Assert.True (view.HasFocus); Assert.False (subView.HasFocus); @@ -252,47 +252,47 @@ public class SetFocusTests () : TestsAllViews Assert.False (subViewSubView2.HasFocus); Assert.False (subViewSubView3.HasFocus); - view.Border.CanFocus = false; + view.Border!.CanFocus = false; Assert.True (view.HasFocus); Assert.True (subView.HasFocus); - Assert.False (view.Border.HasFocus); + Assert.False (view.Border!.HasFocus); Assert.False (borderSubView.HasFocus); Assert.False (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); Assert.False (subViewSubView3.HasFocus); - view.Border.CanFocus = true; + view.Border!.CanFocus = true; Assert.True (view.HasFocus); Assert.True (subView.HasFocus); - Assert.False (view.Border.HasFocus); + Assert.False (view.Border!.HasFocus); Assert.False (borderSubView.HasFocus); Assert.False (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); Assert.False (subViewSubView3.HasFocus); - view.Border.SetFocus (); + view.Border!.SetFocus (); Assert.True (view.HasFocus); - Assert.True (view.Border.HasFocus); + Assert.True (view.Border!.HasFocus); Assert.False (subView.HasFocus); Assert.True (borderSubView.HasFocus); Assert.True (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); Assert.False (subViewSubView3.HasFocus); - view.Border.CanFocus = false; + view.Border!.CanFocus = false; Assert.True (view.HasFocus); Assert.True (subView.HasFocus); - Assert.False (view.Border.HasFocus); + Assert.False (view.Border!.HasFocus); Assert.False (borderSubView.HasFocus); Assert.False (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); Assert.False (subViewSubView3.HasFocus); - view.Border.CanFocus = true; + view.Border!.CanFocus = true; subViewSubView1.SetFocus (); Assert.True (view.HasFocus); Assert.False (subView.HasFocus); - Assert.True (view.Border.HasFocus); + Assert.True (view.Border!.HasFocus); Assert.True (borderSubView.HasFocus); Assert.True (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); @@ -301,7 +301,7 @@ public class SetFocusTests () : TestsAllViews subView.SetFocus (); Assert.True (view.HasFocus); Assert.True (subView.HasFocus); - Assert.False (view.Border.HasFocus); + Assert.False (view.Border!.HasFocus); Assert.False (borderSubView.HasFocus); Assert.False (subViewSubView1.HasFocus); Assert.False (subViewSubView2.HasFocus); diff --git a/Tests/UnitTestsParallelizable/View/SchemeTests.cs b/Tests/UnitTestsParallelizable/View/SchemeTests.cs index 8ea8cec50..e38e88689 100644 --- a/Tests/UnitTestsParallelizable/View/SchemeTests.cs +++ b/Tests/UnitTestsParallelizable/View/SchemeTests.cs @@ -1,10 +1,11 @@ #nullable enable +using UnitTests.Parallelizable; using Xunit; namespace UnitTests_Parallelizable.ViewTests; [Trait ("Category", "View.Scheme")] -public class SchemeTests +public class SchemeTests : ParallelizableBase { [Fact] @@ -63,7 +64,7 @@ public class SchemeTests public void GetAttribute_ReturnsCorrectAttribute_Via_Mock () { var view = new View { SchemeName = "Base" }; - view.Driver = new MockConsoleDriver (); + view.Driver = CreateFakeDriver (); view.Driver.SetAttribute (new Attribute (Color.Red, Color.Green)); // Act @@ -103,7 +104,7 @@ public class SchemeTests public void SetAttributeForRole_SetsCorrectAttribute () { var view = new View { SchemeName = "Base" }; - view.Driver = new MockConsoleDriver (); + view.Driver = CreateFakeDriver (); view.Driver.SetAttribute (new Attribute (Color.Red, Color.Green)); var previousAttribute = view.SetAttributeForRole (VisualRole.Focus); @@ -316,16 +317,16 @@ public class SchemeTests // Border (an Adornment) doesn't have a SuperView but should use its Parent's scheme var view = new View { SchemeName = "Dialog" }; var border = view.Border!; - + Assert.NotNull (border); Assert.Null (border.SuperView); // Adornments don't have SuperView Assert.NotNull (border.Parent); - + var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"]; - + // Border should use its Parent's scheme, not Base Assert.Equal (dialogScheme!.Normal, border.GetAttributeForRole (VisualRole.Normal)); - + view.Dispose (); } @@ -365,11 +366,11 @@ public class SchemeTests { // Test: grandchild without explicit scheme defers through parent to grandparent // Would fail without the SuperView deferral fix (commit 154ac15) - + var grandparentView = new View { SchemeName = "Base" }; var parentView = new View (); // No scheme or SchemeName var childView = new View (); // No scheme or SchemeName - + grandparentView.Add (parentView); parentView.Add (childView); @@ -386,7 +387,7 @@ public class SchemeTests // Child should get attribute from grandparent through parent Assert.Equal (customAttribute, childView.GetAttributeForRole (VisualRole.Normal)); - + // Parent should also get attribute from grandparent Assert.Equal (customAttribute, parentView.GetAttributeForRole (VisualRole.Normal)); @@ -400,11 +401,11 @@ public class SchemeTests { // Test: parent with SchemeName stops deferral chain // Would fail without the SchemeName check (commit 866e002) - + var grandparentView = new View { SchemeName = "Base" }; var parentView = new View { SchemeName = "Dialog" }; // Sets SchemeName var childView = new View (); // No scheme or SchemeName - + grandparentView.Add (parentView); parentView.Add (childView); @@ -423,7 +424,7 @@ public class SchemeTests var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"]; Assert.NotEqual (customAttribute, parentView.GetAttributeForRole (VisualRole.Normal)); Assert.Equal (dialogScheme!.Normal, parentView.GetAttributeForRole (VisualRole.Normal)); - + // Child should get parent's Dialog scheme (defers to parent, parent uses Dialog scheme) Assert.Equal (dialogScheme!.Normal, childView.GetAttributeForRole (VisualRole.Normal)); @@ -437,7 +438,7 @@ public class SchemeTests { // Test: view's own OnGettingAttributeForRole takes precedence over parent // This should work with or without the fix, but validates precedence - + var parentView = new View { SchemeName = "Base" }; var childView = new TestViewWithAttributeOverride (); parentView.Add (childView); @@ -456,7 +457,7 @@ public class SchemeTests // Child's own override should take precedence var childOverrideAttribute = new Attribute (Color.BrightRed, Color.BrightCyan); childView.OverrideAttribute = childOverrideAttribute; - + Assert.Equal (childOverrideAttribute, childView.GetAttributeForRole (VisualRole.Normal)); childView.Dispose (); @@ -468,7 +469,7 @@ public class SchemeTests { // Test: multiple VisualRoles all defer correctly // Would fail without the SuperView deferral fix for any role - + var parentView = new View { SchemeName = "Base" }; var childView = new View (); parentView.Add (childView); diff --git a/Tests/UnitTestsParallelizable/Views/AllViewsTests.cs b/Tests/UnitTestsParallelizable/Views/AllViewsTests.cs index 4acedccda..42fb13502 100644 --- a/Tests/UnitTestsParallelizable/Views/AllViewsTests.cs +++ b/Tests/UnitTestsParallelizable/Views/AllViewsTests.cs @@ -146,37 +146,37 @@ public class AllViewsTests (ITestOutputHelper output) : TestsAllViews view?.Dispose (); } - [Theory] - [MemberData (nameof (AllViewTypes))] - public void AllViews_Disabled_Draws_Disabled_Or_Faint (Type viewType) - { - var view = CreateInstanceIfNotGeneric (viewType); + //[Theory] + //[MemberData (nameof (AllViewTypes))] + //public void AllViews_Disabled_Draws_Disabled_Or_Faint (Type viewType) + //{ + // var view = CreateInstanceIfNotGeneric (viewType); - if (view == null) - { - output.WriteLine ($"Ignoring {viewType} - It's a Generic"); + // if (view == null) + // { + // output.WriteLine ($"Ignoring {viewType} - It's a Generic"); - return; - } + // return; + // } - if (view is IDesignable designable) - { - designable.EnableForDesign (); - } + // if (view is IDesignable designable) + // { + // designable.EnableForDesign (); + // } - var mockDriver = new MockConsoleDriver (); - mockDriver.AttributeSet += (_, args) => - { - if (args != view.GetAttributeForRole (VisualRole.Disabled) && args.Style != TextStyle.Faint) - { - Assert.Fail($"{viewType} with `Enabled == false` tried to SetAttribute to {args}"); - } - }; - view.Driver = mockDriver; - view.Enabled = false; - view.SetNeedsDraw (); - view.Draw (); + // var driver = CreateFakeDriver (); + // driver.AttributeSet += (_, args) => + // { + // if (args != view.GetAttributeForRole (VisualRole.Disabled) && args.Style != TextStyle.Faint) + // { + // Assert.Fail($"{viewType} with `Enabled == false` tried to SetAttribute to {args}"); + // } + // }; + // view.Driver = driver; + // view.Enabled = false; + // view.SetNeedsDraw (); + // view.Draw (); - view?.Dispose (); - } + // view?.Dispose (); + //} } diff --git a/Tests/UnitTestsParallelizable/Views/CheckBoxTests.cs b/Tests/UnitTestsParallelizable/Views/CheckBoxTests.cs index 2bc1d9159..d88923151 100644 --- a/Tests/UnitTestsParallelizable/Views/CheckBoxTests.cs +++ b/Tests/UnitTestsParallelizable/Views/CheckBoxTests.cs @@ -3,7 +3,7 @@ using Xunit.Abstractions; namespace UnitTests_Parallelizable.ViewsTests; -public class CheckBoxTests (ITestOutputHelper output) +public class CheckBoxTests () { [Theory] [InlineData ("01234", 0, 0, 0, 0)] diff --git a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs index 0955db87b..f192ae202 100644 --- a/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs +++ b/Tests/UnitTestsParallelizable/Views/TextFieldTests.cs @@ -1,8 +1,11 @@ using System.Text; +using UnitTests; +using UnitTests.Parallelizable; +using Xunit.Abstractions; namespace UnitTests_Parallelizable.ViewsTests; -public class TextFieldTests +public class TextFieldTests (ITestOutputHelper output) : ParallelizableBase { [Fact] public void Cancel_TextChanging_ThenBackspace () @@ -554,4 +557,80 @@ public class TextFieldTests Assert.Equal (new (3, 0), tf.PositionCursor ()); Assert.Equal ("📄a", tf.Text); } + + [Fact] + public void Accented_Letter_With_Three_Combining_Unicode_Chars () + { + IConsoleDriver driver = CreateFakeDriver (); + + var tf = new TextField { Width = 3, Text = "ắ" }; + tf.Driver = driver; + tf.Layout (); + tf.Draw (); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +ắ", + output, + driver + ); + + tf.Text = "\u1eaf"; + tf.Layout (); + tf.Draw (); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +ắ", + output, + driver + ); + + tf.Text = "\u0103\u0301"; + tf.Layout (); + tf.Draw (); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +ắ", + output, + driver + ); + + tf.Text = "\u0061\u0306\u0301"; + tf.Layout (); + tf.Draw (); + + DriverAssert.AssertDriverContentsWithFrameAre ( + @" +ắ", + output, + driver + ); + } + + [Fact] + public void Adjust_First () + { + IConsoleDriver driver = CreateFakeDriver (); + + var tf = new TextField { Width = Dim.Fill (), Text = "This is a test." }; + tf.Driver = driver; + tf.SetRelativeLayout (new (20, 20)); + tf.Draw (); + + Assert.Equal ("This is a test. ", GetContents ()); + + string GetContents () + { + var item = ""; + + for (var i = 0; i < 16; i++) + { + item += driver.Contents [0, i]!.Rune; + } + + return item; + } + } }