Explorar o código

Application Keybinding tests

Tig hai 1 ano
pai
achega
ab655feadc

+ 47 - 3
Terminal.Gui/Application.cs

@@ -157,6 +157,7 @@ public static partial class Application
         KeyDown = null;
         KeyUp = null;
         SizeChanging = null;
+        ClearKeyBindings ();
 
         Colors.Reset ();
 
@@ -1948,6 +1949,32 @@ public static partial class Application
         _keyBindings [key].Add (view);
     }
 
+    /// <summary>
+    ///    Gets the list of Views that have <see cref="KeyBindingScope.Application"/> key bindings.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
+    /// </remarks>
+    /// <returns>The list of Views that have Application-scoped key bindings.</returns>
+    internal static List<View> GetViewsWithKeyBindings ()
+    {
+        return _keyBindings.Values.SelectMany (v => v).ToList ();
+    }
+
+    /// <summary>
+    ///    Gets the list of Views that have <see cref="KeyBindingScope.Application"/> key bindings for the specified key.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
+    /// </remarks>
+    /// <param name="key">The key to check.</param>
+    /// <param name="views">Outputs the list of views bound to <paramref name="key"/></param>
+    /// <returns><see langword="True"/> if successful.</returns>
+    internal static bool TryGetKeyBindings (Key key, out List<View> views)
+    {
+        return _keyBindings.TryGetValue (key, out views);
+    }
+
     /// <summary>
     ///     Removes an <see cref="KeyBindingScope.Application"/> scoped key binding.
     /// </summary>
@@ -1958,9 +1985,14 @@ public static partial class Application
     /// <param name="view">The view that is bound to the key.</param>
     internal static void RemoveKeyBinding (Key key, View view)
     {
-        if (_keyBindings.TryGetValue (key, out List<View> binding))
+        if (_keyBindings.TryGetValue (key, out List<View> views))
         {
-            binding.Remove (view);
+            views.Remove (view);
+
+            if (views.Count == 0)
+            {
+                _keyBindings.Remove (key);
+            }
         }
     }
 
@@ -1971,7 +2003,7 @@ public static partial class Application
     ///     This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
     /// </remarks>
     /// <param name="view">The view that is bound to the key.</param>
-    internal static void RemoveAllKeyBindings (View view)
+    internal static void ClearKeyBindings (View view)
     {
         foreach (Key key in _keyBindings.Keys)
         {
@@ -1979,5 +2011,17 @@ public static partial class Application
         }
     }
 
+    /// <summary>
+    ///     Removes all <see cref="KeyBindingScope.Application"/> scoped key bindings for the specified view.
+    /// </summary>
+    /// <remarks>
+    ///     This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
+    /// </remarks>
+    /// <param name="view">The view that is bound to the key.</param>
+    internal static void ClearKeyBindings ()
+    {
+        _keyBindings.Clear ();
+    }
+
     #endregion Keyboard handling
 }

+ 1 - 5
Terminal.Gui/Input/KeyBindings.cs

@@ -81,10 +81,6 @@ public class KeyBindings
         else
         {
             Add (key, new KeyBinding (commands, scope));
-            if (scope.FastHasFlags (KeyBindingScope.Application))
-            {
-                Application.AddKeyBinding (key, BoundView);
-            }
         }
     }
 
@@ -120,7 +116,7 @@ public class KeyBindings
     /// <summary>Removes all <see cref="KeyBinding"/> objects from the collection.</summary>
     public void Clear ()
     {
-        Application.RemoveAllKeyBindings (BoundView);
+        Application.ClearKeyBindings (BoundView);
 
         Bindings.Clear ();
     }

+ 4 - 0
UnitTests/Application/ApplicationTests.cs

@@ -193,6 +193,9 @@ public class ApplicationTests
             Assert.Empty (Application._topLevels);
             Assert.Null (Application._mouseEnteredView);
 
+            // Keyboard
+            Assert.Empty (Application.GetViewsWithKeyBindings ());
+
             // Events - Can't check
             //Assert.Null (Application.NotifyNewRunState);
             //Assert.Null (Application.NotifyNewRunState);
@@ -225,6 +228,7 @@ public class ApplicationTests
         Application.AlternateBackwardKey = Key.A;
         Application.AlternateForwardKey = Key.B;
         Application.QuitKey = Key.C;
+        Application.AddKeyBinding(Key.A, new View ());
 
         //Application.OverlappedChildren = new List<View> ();
         //Application.OverlappedTop = 

+ 100 - 30
UnitTests/Application/KeyboardTests.cs

@@ -2,6 +2,9 @@
 
 namespace Terminal.Gui.ApplicationTests;
 
+/// <summary>
+/// Application tests for keyboard support.
+/// </summary>
 public class KeyboardTests
 {
     private readonly ITestOutputHelper _output;
@@ -15,6 +18,46 @@ public class KeyboardTests
 #endif
     }
 
+
+    [Fact]
+    [AutoInitShutdown]
+    public void QuitKey_Getter_Setter ()
+    {
+        Toplevel top = new ();
+        var isQuiting = false;
+
+        top.Closing += (s, e) =>
+                       {
+                           isQuiting = true;
+                           e.Cancel = true;
+                       };
+
+        Application.Begin (top);
+        top.Running = true;
+
+        Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey.KeyCode);
+        Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true);
+        Assert.True (isQuiting);
+
+        isQuiting = false;
+        Application.OnKeyDown (Key.Q.WithCtrl);
+        Assert.True (isQuiting);
+
+        isQuiting = false;
+        Application.QuitKey = Key.C.WithCtrl;
+        Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true);
+        Assert.False (isQuiting);
+        Application.OnKeyDown (Key.Q.WithCtrl);
+        Assert.False (isQuiting);
+
+        Application.OnKeyDown (Application.QuitKey);
+        Assert.True (isQuiting);
+
+        // Reset the QuitKey to avoid throws errors on another tests
+        Application.QuitKey = Key.Q.WithCtrl;
+        top.Dispose ();
+    }
+
     [Fact]
     public void AlternateForwardKey_AlternateBackwardKey_Tests ()
     {
@@ -320,7 +363,7 @@ public class KeyboardTests
 
     [Fact]
     [AutoInitShutdown]
-    public void OnKeyDown_Application_KeyBinding ()
+    public void KeyBinding_OnKeyDown ()
     {
         var view = new ScopedKeyBindingView ();
         var invoked = false;
@@ -365,7 +408,7 @@ public class KeyboardTests
 
     [Fact]
     [AutoInitShutdown]
-    public void OnKeyDown_Application_KeyBinding_Negative ()
+    public void KeyBinding_OnKeyDown_Negative ()
     {
         var view = new ScopedKeyBindingView ();
         var invoked = false;
@@ -391,46 +434,73 @@ public class KeyboardTests
         top.Dispose ();
     }
 
+
     [Fact]
     [AutoInitShutdown]
-    public void QuitKey_Getter_Setter ()
+    public void KeyBinding_AddKeyBinding_Adds ()
     {
-        Toplevel top = new ();
-        var isQuiting = false;
+        View view1 = new ();
+        Application.AddKeyBinding (Key.A, view1);
 
-        top.Closing += (s, e) =>
-                       {
-                           isQuiting = true;
-                           e.Cancel = true;
-                       };
+        View view2 = new ();
+        Application.AddKeyBinding (Key.A, view2);
 
-        Application.Begin (top);
-        top.Running = true;
+        Assert.True (Application.TryGetKeyBindings (Key.A, out List<View> views));
+        Assert.Contains (view1, views);
+        Assert.Contains (view2, views);
 
-        Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey.KeyCode);
-        Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true);
-        Assert.True (isQuiting);
+        Assert.False (Application.TryGetKeyBindings (Key.B, out List<View> _));
+    }
 
-        isQuiting = false;
-        Application.OnKeyDown (Key.Q.WithCtrl);
-        Assert.True (isQuiting);
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBinding_ViewKeyBindings_Add_Adds ()
+    {
+        View view1 = new ();
+        view1.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Save);
+        view1.KeyBindings.Add (Key.B, KeyBindingScope.HotKey, Command.Left);
+        Assert.Single (Application.GetViewsWithKeyBindings ());
 
-        isQuiting = false;
-        Application.QuitKey = Key.C.WithCtrl;
-        Application.Driver.SendKeys ('Q', ConsoleKey.Q, false, false, true);
-        Assert.False (isQuiting);
-        Application.OnKeyDown (Key.Q.WithCtrl);
-        Assert.False (isQuiting);
+        View view2 = new ();
+        view2.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Save);
+        view2.KeyBindings.Add (Key.B, KeyBindingScope.HotKey, Command.Left);
 
-        Application.OnKeyDown (Application.QuitKey);
-        Assert.True (isQuiting);
+        Assert.True (Application.TryGetKeyBindings (Key.A, out List<View> views));
+        Assert.Contains (view1, views);
+        Assert.Contains (view2, views);
 
-        // Reset the QuitKey to avoid throws errors on another tests
-        Application.QuitKey = Key.Q.WithCtrl;
-        top.Dispose ();
+        Assert.False (Application.TryGetKeyBindings (Key.B, out List<View> _));
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBinding_RemoveKeyBinding_Removes ()
+    {
+        View view1 = new ();
+        Application.AddKeyBinding (Key.A, view1);
+
+        Assert.True (Application.TryGetKeyBindings (Key.A, out List<View> views));
+        Assert.Contains (view1, views);
+
+        Application.RemoveKeyBinding (Key.A, view1);
+        Assert.False (Application.TryGetKeyBindings (Key.A, out List<View> _));
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBinding_ViewKeyBindings_RemoveKeyBinding_Removes ()
+    {
+        View view1 = new ();
+        view1.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Save);
+
+        Assert.True (Application.TryGetKeyBindings (Key.A, out List<View> views));
+        Assert.Contains (view1, views);
+
+        view1.KeyBindings.Remove (Key.A);
+        Assert.False (Application.TryGetKeyBindings (Key.A, out List<View> _));
     }
 
-    // test Application key Bindings
+    // Test View for testing Application key Bindings
     public class ScopedKeyBindingView : View
     {
         public ScopedKeyBindingView ()