瀏覽代碼

Fixed a buinch of bugs. Updated unit tests including some that test all views to utilize TheoryData

Tig 1 年之前
父節點
當前提交
667912a610

+ 1 - 1
Terminal.Gui/Application.cs

@@ -1360,7 +1360,7 @@ public static partial class Application
     /// <summary>Event fired when a mouse move or click occurs. Coordinates are screen relative.</summary>
     /// <remarks>
     ///     <para>
-    ///         Use this event to receive mouse events in screen coordinates. Use <see cref="Responder.MouseEvent"/> to
+    ///         Use this event to receive mouse events in screen coordinates. Use <see cref="MouseEvent"/> to
     ///         receive mouse events relative to a <see cref="View"/>'s bounds.
     ///     </para>
     ///     <para>The <see cref="MouseEvent.View"/> will contain the <see cref="View"/> that contains the mouse coordinates.</para>

+ 2 - 2
Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs

@@ -163,7 +163,7 @@ public static class EscSeqUtils
     /// <param name="key">The <see cref="ConsoleKey"/> which may changes.</param>
     /// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
     /// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
-    /// <param name="c1Control">The control returned by the <see cref="GetC1ControlChar(char)"/> method.</param>
+    /// <param name="c1Control">The control returned by the <see cref="GetC1ControlChar"/> method.</param>
     /// <param name="code">The code returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
     /// <param name="values">The values returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
     /// <param name="terminator">The terminator returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
@@ -406,7 +406,7 @@ public static class EscSeqUtils
     /// </summary>
     /// <param name="kChar">The array with all chars.</param>
     /// <returns>
-    ///     The c1Control returned by <see cref="GetC1ControlChar(char)"/>, code, values and terminating.
+    ///     The c1Control returned by <see cref="GetC1ControlChar"/>, code, values and terminating.
     /// </returns>
     public static (string c1Control, string code, string [] values, string terminating) GetEscapeResult (char [] kChar)
     {

+ 5 - 46
Terminal.Gui/Input/Responder.cs

@@ -1,35 +1,14 @@
-//
-// Core.cs: The core engine for gui.cs
-//
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
-// Pending:
-//   - Check for NeedDisplay on the hierarchy and repaint
-//   - Layout support
-//   - "Colors" type or "Attributes" type?
-//   - What to surface as "BackgroundCOlor" when clearing a window, an attribute or colors?
-//
-// Optimziations
-//   - Add rendering limitation to the exposed area
-
-using System.Reflection;
+using System.Reflection;
 
 namespace Terminal.Gui;
 
 /// <summary>Responder base class implemented by objects that want to participate on keyboard and mouse input.</summary>
 public class Responder : IDisposable
 {
-    private bool disposedValue;
-
-
-    /// <summary>Gets or sets a value indicating whether this <see cref="Responder"/> can respond to user interaction.</summary>
-    public virtual bool Enabled { get; set; } = true;
-
-    /// <summary>Gets or sets a value indicating whether this <see cref="Responder"/> and all its child controls are displayed.</summary>
-    public virtual bool Visible { get; set; } = true;
+    private bool _disposedValue;
 
     /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resource.</summary>
+
     public void Dispose ()
     {
         // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
@@ -49,26 +28,6 @@ public class Responder : IDisposable
     /// <summary>Event raised when <see cref="Dispose()"/> has been called to signal that this object is being disposed.</summary>
     public event EventHandler Disposing;
 
-    /// <summary>Method invoked when the <see cref="CanFocus"/> property from a view is changed.</summary>
-    public virtual void OnCanFocusChanged () { }
-
-    /// <summary>Method invoked when the <see cref="Enabled"/> property from a view is changed.</summary>
-    public virtual void OnEnabledChanged () { }
-
-    /// <summary>Method invoked when a view gets focus.</summary>
-    /// <param name="view">The view that is losing focus.</param>
-    /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
-    public virtual bool OnEnter (View view) { return false; }
-
-    /// <summary>Method invoked when a view loses focus.</summary>
-    /// <param name="view">The view that is getting focus.</param>
-    /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
-    public virtual bool OnLeave (View view) { return false; }
-
-
-    /// <summary>Method invoked when the <see cref="Visible"/> property from a view is changed.</summary>
-    public virtual void OnVisibleChanged () { }
-
     /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
     /// <remarks>
     ///     If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and
@@ -78,14 +37,14 @@ public class Responder : IDisposable
     /// <param name="disposing"></param>
     protected virtual void Dispose (bool disposing)
     {
-        if (!disposedValue)
+        if (!_disposedValue)
         {
             if (disposing)
             {
                 // TODO: dispose managed state (managed objects)
             }
 
-            disposedValue = true;
+            _disposedValue = true;
         }
     }
 

+ 12 - 4
Terminal.Gui/View/Adornment/Adornment.cs

@@ -86,10 +86,18 @@ public class Adornment : View
             Thickness prev = _thickness;
             _thickness = value;
 
-            if (IsInitialized && prev != _thickness)
+            if (prev != _thickness)
             {
-                Parent?.SetNeedsLayout ();
-                Parent?.LayoutSubviews ();
+                if (Parent?.IsInitialized == false)
+                {
+                    // When initialized Parent.LayoutSubViews will cause a LayoutAdornments
+                    Parent?.LayoutAdornments ();
+                }
+                else
+                {
+                    Parent?.SetNeedsLayout ();
+                    Parent?.LayoutSubviews ();
+                }
                 OnThicknessChanged (prev);
             }
         }
@@ -162,7 +170,7 @@ public class Adornment : View
     public override bool OnRenderLineCanvas () { return false; }
 
     /// <summary>Called whenever the <see cref="Thickness"/> property changes.</summary>
-    public virtual void OnThicknessChanged (Thickness previousThickness)
+    public void OnThicknessChanged (Thickness previousThickness)
     {
         ThicknessChanged?.Invoke (
                                   this,

+ 14 - 4
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -558,7 +558,7 @@ public partial class View
     /// <summary>Overriden by <see cref="Adornment"/> to do nothing, as the <see cref="Adornment"/> does not have adornments.</summary>
     internal virtual void LayoutAdornments ()
     {
-        if (!IsInitialized || Margin is null)
+        if (Margin is null)
         {
             return; // CreateAdornments () has not been called yet
         }
@@ -573,7 +573,11 @@ public partial class View
         }
         Margin.SetNeedsLayout ();
         Margin.SetNeedsDisplay ();
-        Margin.LayoutSubviews ();
+
+        if (IsInitialized)
+        {
+            Margin.LayoutSubviews ();
+        }
 
         Rectangle border = Margin.Thickness.GetInside (Margin.Frame);
 
@@ -587,7 +591,10 @@ public partial class View
         }
         Border.SetNeedsLayout ();
         Border.SetNeedsDisplay ();
-        Border.LayoutSubviews ();
+        if (IsInitialized)
+        {
+            Border.LayoutSubviews ();
+        }
 
         Rectangle padding = Border.Thickness.GetInside (Border.Frame);
 
@@ -601,7 +608,10 @@ public partial class View
         }
         Padding.SetNeedsLayout ();
         Padding.SetNeedsDisplay ();
-        Padding.LayoutSubviews ();
+        if (IsInitialized)
+        {
+            Padding.LayoutSubviews ();
+        }
     }
 
     #endregion Adornments

+ 56 - 57
Terminal.Gui/View/View.cs

@@ -286,51 +286,46 @@ public partial class View : Responder, ISupportInitializeNotification
 
     #region Visibility
 
+    private bool _enabled = true;
     private bool _oldEnabled;
 
-    /// <inheritdoc/>
-    public override bool Enabled
+    /// <summary>Gets or sets a value indicating whether this <see cref="Responder"/> can respond to user interaction.</summary>
+    public virtual bool Enabled
     {
-        get => base.Enabled;
+        get => _enabled;
         set
         {
-            if (base.Enabled != value)
+            if (_enabled == value)
             {
-                if (value)
-                {
-                    if (SuperView is null || SuperView?.Enabled == true)
-                    {
-                        base.Enabled = value;
-                    }
-                }
-                else
-                {
-                    base.Enabled = value;
-                }
+                return;
+            }
 
-                if (!value && HasFocus)
-                {
-                    SetHasFocus (false, this);
-                }
+            _enabled = value;
 
-                OnEnabledChanged ();
-                SetNeedsDisplay ();
+            if (!_enabled && HasFocus)
+            {
+                SetHasFocus (false, this);
+            }
+
+            OnEnabledChanged ();
+            SetNeedsDisplay ();
+
+            if (_subviews is null)
+            {
+                return;
+            }
 
-                if (_subviews is { })
+            foreach (View view in _subviews)
+            {
+                if (!_enabled)
+                {
+                    view._oldEnabled = view.Enabled;
+                    view.Enabled = _enabled;
+                }
+                else
                 {
-                    foreach (View view in _subviews)
-                    {
-                        if (!value)
-                        {
-                            view._oldEnabled = view.Enabled;
-                            view.Enabled = false;
-                        }
-                        else
-                        {
-                            view.Enabled = view._oldEnabled;
-                            view._addingView = false;
-                        }
-                    }
+                    view.Enabled = view._oldEnabled;
+                    view._addingView = _enabled;
                 }
             }
         }
@@ -339,40 +334,44 @@ public partial class View : Responder, ISupportInitializeNotification
     /// <summary>Event fired when the <see cref="Enabled"/> value is being changed.</summary>
     public event EventHandler EnabledChanged;
 
-    /// <inheritdoc/>
-    public override void OnEnabledChanged () { EnabledChanged?.Invoke (this, EventArgs.Empty); }
+    /// <summary>Method invoked when the <see cref="Enabled"/> property from a view is changed.</summary>
+    public virtual void OnEnabledChanged () { EnabledChanged?.Invoke (this, EventArgs.Empty); }
 
-    /// <inheritdoc/>
-    public override bool Visible
+    private bool _visible = true;
+    /// <summary>Gets or sets a value indicating whether this <see cref="Responder"/> and all its child controls are displayed.</summary>
+    public virtual bool Visible
     {
-        get => base.Visible;
+        get => _visible;
         set
         {
-            if (base.Visible != value)
+            if (_visible == value)
             {
-                base.Visible = value;
+                return;
+            }
 
-                if (!value)
+            _visible = value;
+
+            if (!_visible)
+            {
+                if (HasFocus)
                 {
-                    if (HasFocus)
-                    {
-                        SetHasFocus (false, this);
-                    }
-
-                    if (IsInitialized && ClearOnVisibleFalse)
-                    {
-                        Clear ();
-                    }
+                    SetHasFocus (false, this);
                 }
 
-                OnVisibleChanged ();
-                SetNeedsDisplay ();
+                if (IsInitialized && ClearOnVisibleFalse)
+                {
+                    Clear ();
+                }
             }
+
+            OnVisibleChanged ();
+            SetNeedsDisplay ();
         }
     }
 
-    /// <inheritdoc/>
-    public override void OnVisibleChanged () { VisibleChanged?.Invoke (this, EventArgs.Empty); }
+
+    /// <summary>Method invoked when the <see cref="Visible"/> property from a view is changed.</summary>
+    public virtual void OnVisibleChanged () { VisibleChanged?.Invoke (this, EventArgs.Empty); }
 
     /// <summary>Gets or sets whether a view is cleared if the <see cref="Visible"/> property is <see langword="false"/>.</summary>
     public bool ClearOnVisibleFalse { get; set; } = true;
@@ -380,7 +379,7 @@ public partial class View : Responder, ISupportInitializeNotification
     /// <summary>Event fired when the <see cref="Visible"/> value is being changed.</summary>
     public event EventHandler VisibleChanged;
 
-    private bool CanBeVisible (View view)
+    private static bool CanBeVisible (View view)
     {
         if (!view.Visible)
         {

+ 4 - 4
Terminal.Gui/View/ViewKeyboard.cs

@@ -646,17 +646,17 @@ public partial class View
             return true;
         }
 
-        if (ProcessAdornmentKeyBindings (Margin, keyEvent, ref handled))
+        if (Margin is {} && ProcessAdornmentKeyBindings (Margin, keyEvent, ref handled))
         {
             return true;
         }
 
-        if (ProcessAdornmentKeyBindings (Padding, keyEvent, ref handled))
+        if (Padding is {} && ProcessAdornmentKeyBindings (Padding, keyEvent, ref handled))
         {
             return true;
         }
 
-        if (ProcessAdornmentKeyBindings (Border, keyEvent, ref handled))
+        if (Border is {} && ProcessAdornmentKeyBindings (Border, keyEvent, ref handled))
         {
             return true;
         }
@@ -671,7 +671,7 @@ public partial class View
 
     private bool ProcessAdornmentKeyBindings (Adornment adornment, Key keyEvent, ref bool? handled)
     {
-        foreach (View subview in adornment?.Subviews!)
+        foreach (View subview in adornment?.Subviews)
         {
             handled = subview.OnInvokingKeyBindings (keyEvent);
 

+ 68 - 78
Terminal.Gui/View/ViewSubViews.cs

@@ -353,24 +353,17 @@ public partial class View
         }
     }
 
+
     /// <summary>Event fired when the <see cref="CanFocus"/> value is being changed.</summary>
     public event EventHandler CanFocusChanged;
 
-    /// <inheritdoc/>
-    public override void OnCanFocusChanged () { CanFocusChanged?.Invoke (this, EventArgs.Empty); }
+    /// <summary>Method invoked when the <see cref="CanFocus"/> property from a view is changed.</summary>
+    public virtual void OnCanFocusChanged () { CanFocusChanged?.Invoke (this, EventArgs.Empty); }
 
     private bool _oldCanFocus;
     private bool _canFocus;
 
     /// <summary>Gets or sets a value indicating whether this <see cref="View"/> can focus.</summary>
-    /// <remarks>
-    ///     Override of <see cref="Responder"/>.<see cref="Responder.CanFocus"/>.
-    ///     <para/>
-    ///     Get accessor directly returns <see cref="Responder"/>.<see cref="Responder.CanFocus"/>.
-    ///     <para/>
-    ///     Set accessor validates <see langword="value"/> before setting <see cref="Responder"/>.
-    ///     <see cref="Responder.CanFocus"/>.
-    /// </remarks>
     public bool CanFocus
     {
         get => _canFocus;
@@ -381,88 +374,92 @@ public partial class View
                 throw new InvalidOperationException ("Cannot set CanFocus to true if the SuperView CanFocus is false!");
             }
 
-            if (_canFocus != value)
+            if (_canFocus == value)
             {
-                _canFocus = value;
+                return;
+            }
 
-                switch (value)
-                {
-                    case false when _tabIndex > -1:
-                        TabIndex = -1;
+            _canFocus = value;
 
-                        break;
-                    case true when SuperView?.CanFocus == false && _addingView:
-                        SuperView.CanFocus = true;
+            switch (_canFocus)
+            {
+                case false when _tabIndex > -1:
+                    TabIndex = -1;
 
-                        break;
-                }
+                    break;
+                case true when SuperView?.CanFocus == false && _addingView:
+                    SuperView.CanFocus = true;
 
-                if (value && _tabIndex == -1)
-                {
-                    TabIndex = SuperView is { } ? SuperView._tabIndexes.IndexOf (this) : -1;
-                }
+                    break;
+            }
 
-                TabStop = value;
+            if (_canFocus && _tabIndex == -1)
+            {
+                TabIndex = SuperView is { } ? SuperView._tabIndexes.IndexOf (this) : -1;
+            }
 
-                if (!value && SuperView?.Focused == this)
-                {
-                    SuperView.Focused = null;
-                }
+            TabStop = _canFocus;
 
-                if (!value && HasFocus)
-                {
-                    SetHasFocus (false, this);
-                    SuperView?.EnsureFocus ();
+            if (!_canFocus && SuperView?.Focused == this)
+            {
+                SuperView.Focused = null;
+            }
 
-                    if (SuperView is { } && SuperView.Focused is null)
-                    {
-                        SuperView.FocusNext ();
+            if (!_canFocus && HasFocus)
+            {
+                SetHasFocus (false, this);
+                SuperView?.EnsureFocus ();
 
-                        if (SuperView.Focused is null && Application.Current is { })
-                        {
-                            Application.Current.FocusNext ();
-                        }
+                if (SuperView is { } && SuperView.Focused is null)
+                {
+                    SuperView.FocusNext ();
 
-                        Application.BringOverlappedTopToFront ();
+                    if (SuperView.Focused is null && Application.Current is { })
+                    {
+                        Application.Current.FocusNext ();
                     }
+
+                    Application.BringOverlappedTopToFront ();
                 }
+            }
 
-                if (_subviews is { } && IsInitialized)
+            if (_subviews is { } && IsInitialized)
+            {
+                foreach (View view in _subviews)
                 {
-                    foreach (View view in _subviews)
+                    if (view.CanFocus != value)
                     {
-                        if (view.CanFocus != value)
+                        if (!value)
                         {
-                            if (!value)
-                            {
-                                view._oldCanFocus = view.CanFocus;
-                                view._oldTabIndex = view._tabIndex;
-                                view.CanFocus = false;
-                                view._tabIndex = -1;
-                            }
-                            else
+                            view._oldCanFocus = view.CanFocus;
+                            view._oldTabIndex = view._tabIndex;
+                            view.CanFocus = false;
+                            view._tabIndex = -1;
+                        }
+                        else
+                        {
+                            if (_addingView)
                             {
-                                if (_addingView)
-                                {
-                                    view._addingView = true;
-                                }
-
-                                view.CanFocus = view._oldCanFocus;
-                                view._tabIndex = view._oldTabIndex;
-                                view._addingView = false;
+                                view._addingView = true;
                             }
+
+                            view.CanFocus = view._oldCanFocus;
+                            view._tabIndex = view._oldTabIndex;
+                            view._addingView = false;
                         }
                     }
                 }
-
-                OnCanFocusChanged ();
-                SetNeedsDisplay ();
             }
+
+            OnCanFocusChanged ();
+            SetNeedsDisplay ();
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
+    /// <summary>Method invoked when a view gets focus.</summary>
+    /// <param name="view">The view that is losing focus.</param>
+    /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
+    public virtual bool OnEnter (View view)
     {
         var args = new FocusEventArgs (view);
         Enter?.Invoke (this, args);
@@ -472,16 +469,14 @@ public partial class View
             return true;
         }
 
-        if (base.OnEnter (view))
-        {
-            return true;
-        }
-
         return false;
     }
 
-    /// <inheritdoc/>
-    public override bool OnLeave (View view)
+
+    /// <summary>Method invoked when a view loses focus.</summary>
+    /// <param name="view">The view that is getting focus.</param>
+    /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
+    public virtual bool OnLeave (View view)
     {
         var args = new FocusEventArgs (view);
         Leave?.Invoke (this, args);
@@ -491,11 +486,6 @@ public partial class View
             return true;
         }
 
-        if (base.OnLeave (view))
-        {
-            return true;
-        }
-
         Driver?.SetCursorVisibility (CursorVisibility.Invisible);
 
         return false;

+ 0 - 2
UnitTests/Input/ResponderTests.cs

@@ -222,8 +222,6 @@ public class ResponderTests
         var r = new Responder ();
         Assert.NotNull (r);
         Assert.Equal ("Terminal.Gui.Responder", r.ToString ());
-        Assert.True (r.Enabled);
-        Assert.True (r.Visible);
         r.Dispose ();
     }
 

+ 45 - 27
UnitTests/TestHelpers.cs

@@ -228,19 +228,7 @@ internal partial class TestHelpers
                     case 0:
                         throw new Exception (
                                              $"{DriverContentsToString (driver)}\n"
-                                             + $"Expected Attribute {
-                                                 val
-                                             } (PlatformColor = {
-                                                 val.Value.PlatformColor
-                                             }) at Contents[{
-                                                 line
-                                             },{
-                                                 c
-                                             }] {
-                                                 contents [line, c]
-                                             } ((PlatformColor = {
-                                                 contents [line, c].Attribute.Value.PlatformColor
-                                             }) was not found.\n"
+                                             + $"Expected Attribute {val} (PlatformColor = {val.Value.PlatformColor}) at Contents[{line},{c}] {contents [line, c]} ((PlatformColor = {contents [line, c].Attribute.Value.PlatformColor}) was not found.\n"
                                              + $"  Expected: {string.Join (",", expectedAttributes.Select (c => c))}\n"
                                              + $"  But Was: <not found>"
                                             );
@@ -438,7 +426,7 @@ internal partial class TestHelpers
 
         // standardize line endings for the comparison
         expectedLook = expectedLook.ReplaceLineEndings ();
-        actualLook = actualLook.ReplaceLineEndings();
+        actualLook = actualLook.ReplaceLineEndings ();
 
         // Remove the first and the last line ending from the expectedLook
         if (expectedLook.StartsWith (Environment.NewLine))
@@ -522,6 +510,7 @@ internal partial class TestHelpers
         return sb.ToString ();
     }
 
+    // TODO: Update all tests that use GetALlViews to use GetAllViewsTheoryData instead
     /// <summary>Gets a list of instances of all classes derived from View.</summary>
     /// <returns>List of View objects</returns>
     public static List<View> GetAllViews ()
@@ -533,10 +522,39 @@ internal partial class TestHelpers
                                             && type.IsPublic
                                             && type.IsSubclassOf (typeof (View))
                                    )
-                            .Select (type => GetTypeInitializer (type, type.GetConstructor (Array.Empty<Type> ())))
+                            .Select (type => CreateView (type, type.GetConstructor (Array.Empty<Type> ())))
                             .ToList ();
     }
 
+    public static TheoryData<View, string> GetAllViewsTheoryData ()
+    {
+        // TODO: Figure out how to simplify this. I couldn't figure out how to not have to iterate over ret.
+        (View view, string name)[] ret =
+            typeof (View).Assembly
+                               .GetTypes ()
+                               .Where (
+                                       type => type.IsClass
+                                               && !type.IsAbstract
+                                               && type.IsPublic
+                                               && type.IsSubclassOf (typeof (View))
+                                      )
+                               .Select (
+                                        type => (
+                                                    view: CreateView (
+                                                                   type, type.GetConstructor (Array.Empty<Type> ())),
+                                                    name: type.Name)
+                                        ).ToArray();
+
+        TheoryData<View, string> td = new ();
+        foreach ((View view, string name) in ret)
+        {
+            td.Add(view, name);
+        }
+
+        return td;
+    }
+
+
     /// <summary>
     ///     Verifies the console used all the <paramref name="expectedColors"/> 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
@@ -638,9 +656,9 @@ internal partial class TestHelpers
         }
     }
 
-    private static View GetTypeInitializer (Type type, ConstructorInfo ctor)
+    public static View CreateView (Type type, ConstructorInfo ctor)
     {
-        View viewType = null;
+        View view = null;
 
         if (type.IsGenericType && type.IsTypeDefinition)
         {
@@ -694,17 +712,17 @@ internal partial class TestHelpers
 
             if (type.IsGenericType && !type.IsTypeDefinition)
             {
-                viewType = (View)Activator.CreateInstance (type);
-                Assert.IsType (type, viewType);
+                view = (View)Activator.CreateInstance (type);
+                Assert.IsType (type, view);
             }
             else
             {
-                viewType = (View)ctor.Invoke (pTypes.ToArray ());
-                Assert.IsType (type, viewType);
+                view = (View)ctor.Invoke (pTypes.ToArray ());
+                Assert.IsType (type, view);
             }
         }
 
-        return viewType;
+        return view;
     }
 
     [GeneratedRegex ("^\\s+", RegexOptions.Multiline)]
@@ -715,11 +733,11 @@ internal partial class TestHelpers
         string replaced = toReplace;
 
         replaced = Environment.NewLine.Length switch
-                   {
-                       2 when !replaced.Contains ("\r\n") => replaced.Replace ("\n", Environment.NewLine),
-                       1 => replaced.Replace ("\r\n", Environment.NewLine),
-                       var _ => replaced
-                   };
+        {
+            2 when !replaced.Contains ("\r\n") => replaced.Replace ("\n", Environment.NewLine),
+            1 => replaced.Replace ("\r\n", Environment.NewLine),
+            var _ => replaced
+        };
 
         return replaced;
     }

+ 7 - 3
UnitTests/View/Adornment/AdornmentSubViewTests.cs

@@ -14,15 +14,17 @@ public class AdornmentSubViewTests (ITestOutputHelper output)
     [InlineData (2, 1, true)]
     public void Adornment_WithSubView_FindDeepestView_Finds (int viewMargin, int subViewMargin, bool expectedFound)
     {
-        var view = new View () {
+        var view = new View ()
+        {
             Width = 10,
             Height = 10
         };
         view.Margin.Thickness = new Thickness (viewMargin);
 
-        var subView = new View () {
+        var subView = new View ()
+        {
             X = 0,
-            Y =0,
+            Y = 0,
             Width = 5,
             Height = 5
         };
@@ -65,6 +67,8 @@ public class AdornmentSubViewTests (ITestOutputHelper output)
         var view = new View ();
         var subView = new View ();
         view.Margin.Add (subView);
+        view.BeginInit ();
+        view.EndInit ();
         var raised = false;
 
         subView.LayoutStarted += LayoutStarted;

+ 48 - 51
UnitTests/View/KeyboardEventTests.cs

@@ -4,59 +4,56 @@
 
 namespace Terminal.Gui.ViewTests;
 
-public class KeyboardEventTests
+public class KeyboardEventTests (ITestOutputHelper output)
 {
-    private readonly ITestOutputHelper _output;
-    public KeyboardEventTests (ITestOutputHelper output) { _output = output; }
+    public static TheoryData<View, string> AllViews => TestHelpers.GetAllViewsTheoryData ();
 
     /// <summary>
-    ///     This tests that when a new key down event is sent to the view the view will fire the 3 key-down related
+    ///     This tests that when a new key down event is sent to the view  will fire the 3 key-down related
     ///     events: KeyDown, InvokingKeyBindings, and ProcessKeyDown. Note that KeyUp is independent.
     /// </summary>
-    [Fact]
-    public void AllViews_KeyDown_All_EventsFire ()
+    [Theory]
+    [MemberData (nameof (AllViews))]
+    public void AllViews_KeyDown_All_EventsFire (View view, string viewName)
     {
-        foreach (View view in TestHelpers.GetAllViews ())
+        if (view == null)
         {
-            if (view == null)
-            {
-                _output.WriteLine ($"ERROR: null view from {nameof (TestHelpers.GetAllViews)}");
+            output.WriteLine ($"ERROR: Skipping generic view: {viewName}");
 
-                continue;
-            }
+            return;
+        }
 
-            _output.WriteLine ($"Testing {view.GetType ().Name}");
+        output.WriteLine ($"Testing {viewName}");
 
-            var keyDown = false;
+        var keyDown = false;
 
-            view.KeyDown += (s, a) =>
-                            {
-                                a.Handled = false; // don't handle it so the other events are called
-                                keyDown = true;
-                            };
+        view.KeyDown += (s, a) =>
+                        {
+                            a.Handled = false; // don't handle it so the other events are called
+                            keyDown = true;
+                        };
 
-            var invokingKeyBindings = false;
+        var invokingKeyBindings = false;
 
-            view.InvokingKeyBindings += (s, a) =>
-                                        {
-                                            a.Handled = false; // don't handle it so the other events are called
-                                            invokingKeyBindings = true;
-                                        };
+        view.InvokingKeyBindings += (s, a) =>
+                                    {
+                                        a.Handled = false; // don't handle it so the other events are called
+                                        invokingKeyBindings = true;
+                                    };
 
-            var keyDownProcessed = false;
+        var keyDownProcessed = false;
 
-            view.ProcessKeyDown += (s, a) =>
-                                   {
-                                       a.Handled = true;
-                                       keyDownProcessed = true;
-                                   };
+        view.ProcessKeyDown += (s, a) =>
+                               {
+                                   a.Handled = true;
+                                   keyDownProcessed = true;
+                               };
 
-            Assert.True (view.NewKeyDownEvent (Key.A)); // this will be true because the ProcessKeyDown event handled it
-            Assert.True (keyDown);
-            Assert.True (invokingKeyBindings);
-            Assert.True (keyDownProcessed);
-            view.Dispose ();
-        }
+        Assert.True (view.NewKeyDownEvent (Key.A)); // this will be true because the ProcessKeyDown event handled it
+        Assert.True (keyDown);
+        Assert.True (invokingKeyBindings);
+        Assert.True (keyDownProcessed);
+        view.Dispose ();
     }
 
     /// <summary>
@@ -70,12 +67,12 @@ public class KeyboardEventTests
         {
             if (view == null)
             {
-                _output.WriteLine ($"ERROR: null view from {nameof (TestHelpers.GetAllViews)}");
+                output.WriteLine ($"ERROR: null view from {nameof (TestHelpers.GetAllViews)}");
 
                 continue;
             }
 
-            _output.WriteLine ($"Testing {view.GetType ().Name}");
+            output.WriteLine ($"Testing {view.GetType ().Name}");
 
             var keyUp = false;
 
@@ -133,24 +130,24 @@ public class KeyboardEventTests
         //Assert.True (view.OnProcessKeyDownWasCalled);
 
         view.NewKeyDownEvent (
-                              new Key (
-                                       KeyCode.Null
-                                       | (shift ? KeyCode.ShiftMask : 0)
-                                       | (alt ? KeyCode.AltMask : 0)
-                                       | (control ? KeyCode.CtrlMask : 0)
-                                      )
+                              new (
+                                   KeyCode.Null
+                                   | (shift ? KeyCode.ShiftMask : 0)
+                                   | (alt ? KeyCode.AltMask : 0)
+                                   | (control ? KeyCode.CtrlMask : 0)
+                                  )
                              );
         Assert.True (keyPressed);
         Assert.True (view.OnKeyDownContinued);
         Assert.True (view.OnKeyPressedContinued);
 
         view.NewKeyUpEvent (
-                            new Key (
-                                     KeyCode.Null
-                                     | (shift ? KeyCode.ShiftMask : 0)
-                                     | (alt ? KeyCode.AltMask : 0)
-                                     | (control ? KeyCode.CtrlMask : 0)
-                                    )
+                            new (
+                                 KeyCode.Null
+                                 | (shift ? KeyCode.ShiftMask : 0)
+                                 | (alt ? KeyCode.AltMask : 0)
+                                 | (control ? KeyCode.CtrlMask : 0)
+                                )
                            );
         Assert.True (keyUp);
         Assert.True (view.OnKeyUpContinued);

+ 3 - 0
UnitTests/View/ViewTests.cs

@@ -744,6 +744,9 @@ At 0,0
         // Parameterless
         var r = new View ();
         Assert.NotNull (r);
+        Assert.True (r.Enabled);
+        Assert.True (r.Visible);
+
         Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
         Assert.Equal ($"View(){r.Bounds}", r.ToString ());
         Assert.False (r.CanFocus);

+ 37 - 41
UnitTests/Views/AllViewsTests.cs

@@ -3,60 +3,56 @@ using Xunit.Abstractions;
 
 namespace Terminal.Gui.ViewsTests;
 
-public class AllViewsTests
+public class AllViewsTests (ITestOutputHelper output)
 {
-    private readonly ITestOutputHelper _output;
-    public AllViewsTests (ITestOutputHelper output) { _output = output; }
+    // TODO: Update all these tests to use AllViews like AllViews_Center_Properly does
+    public static TheoryData<View, string> AllViews => TestHelpers.GetAllViewsTheoryData ();
 
-    [Fact]
-    public void AllViews_Center_Properly ()
+    [Theory]
+    [MemberData (nameof (AllViews))]
+    public void AllViews_Center_Properly (View view, string viewName)
     {
         // See https://github.com/gui-cs/Terminal.Gui/issues/3156
 
-        foreach (Type type in GetAllViewClasses ())
+        if (view == null)
         {
-            Application.Init (new FakeDriver ());
-            View view = CreateViewFromType (type, type.GetConstructor (Array.Empty<Type> ()));
+            output.WriteLine ($"Ignoring {viewName} - It's a Generic");
+            Application.Shutdown ();
 
-            if (view == null)
-            {
-                _output.WriteLine ($"Ignoring {type} - It's a Generic");
-                Application.Shutdown ();
+            return;
+        }
 
-                continue;
-            }
+        view.X = Pos.Center ();
+        view.Y = Pos.Center ();
 
-            view.X = Pos.Center ();
-            view.Y = Pos.Center ();
+        // Turn off AutoSize
+        view.AutoSize = false;
 
-            // Turn off AutoSize
-            view.AutoSize = false;
+        // Ensure the view has positive dimensions
+        view.Width = 10;
+        view.Height = 10;
 
-            // Ensure the view has positive dimensions
-            view.Width = 10;
-            view.Height = 10;
+        var frame = new View { X = 0, Y = 0, Width = 50, Height = 50 };
+        frame.Add (view);
+        frame.BeginInit ();
+        frame.EndInit ();
+        frame.LayoutSubviews ();
 
-            var frame = new View { X = 0, Y = 0, Width = 50, Height = 50 };
-            frame.Add (view);
-            frame.BeginInit ();
-            frame.EndInit ();
-            frame.LayoutSubviews ();
+        // What's the natural width/height?
+        int expectedX = (frame.Frame.Width - view.Frame.Width) / 2;
+        int expectedY = (frame.Frame.Height - view.Frame.Height) / 2;
 
-            // What's the natural width/height?
-            int expectedX = (frame.Frame.Width - view.Frame.Width) / 2;
-            int expectedY = (frame.Frame.Height - view.Frame.Height) / 2;
+        Assert.True (
+                     view.Frame.Left == expectedX,
+                     $"{view} did not center horizontally. Expected: {expectedX}. Actual: {view.Frame.Left}"
+                    );
 
-            Assert.True (
-                         view.Frame.Left == expectedX,
-                         $"{view} did not center horizontally. Expected: {expectedX}. Actual: {view.Frame.Left}"
-                        );
+        Assert.True (
+                     view.Frame.Top == expectedY,
+                     $"{view} did not center vertically. Expected: {expectedY}. Actual: {view.Frame.Top}"
+                    );
+        Application.Shutdown ();
 
-            Assert.True (
-                         view.Frame.Top == expectedY,
-                         $"{view} did not center vertically. Expected: {expectedY}. Actual: {view.Frame.Top}"
-                        );
-            Application.Shutdown ();
-        }
     }
 
     [Fact]
@@ -64,7 +60,7 @@ public class AllViewsTests
     {
         foreach (Type type in GetAllViewClasses ())
         {
-            _output.WriteLine ($"Testing {type.Name}");
+            output.WriteLine ($"Testing {type.Name}");
 
             Application.Init (new FakeDriver ());
 
@@ -73,7 +69,7 @@ public class AllViewsTests
 
             if (vType == null)
             {
-                _output.WriteLine ($"Ignoring {type} - It's a Generic");
+                output.WriteLine ($"Ignoring {type} - It's a Generic");
                 Application.Shutdown ();
 
                 continue;