Переглянути джерело

Added Application.Mouse tests

Tig 10 місяців тому
батько
коміт
1dd2d9f38c

+ 1 - 1
Terminal.Gui/Application/Application.Mouse.cs

@@ -128,7 +128,7 @@ public static partial class Application // Mouse handling
     /// </remarks>
     public static event EventHandler<MouseEvent>? MouseEvent;
 
-    /// <summary>Called when a mouse event occurs. Raises the <see cref="MouseEvent"/> event.</summary>
+    /// <summary>Called when a mouse event is raised by the driver.</summary>
     /// <remarks>This method can be used to simulate a mouse event, e.g. in unit tests.</remarks>
     /// <param name="mouseEvent">The mouse event with coordinates relative to the screen.</param>
     internal static void OnMouseEvent (MouseEvent mouseEvent)

+ 2 - 7
Terminal.Gui/View/View.Mouse.cs

@@ -323,7 +323,7 @@ public partial class View // Mouse APIs
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         A view must be visible to receive Enter/Leave events.
+    ///         A view must be visible to receive Enter events (Leave events are always received).
     ///     </para>
     ///     <para>
     ///         This method calls <see cref="OnMouseEnter"/> to raise the <see cref="MouseEnter"/> event.
@@ -376,7 +376,7 @@ public partial class View // Mouse APIs
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         A view must be visible to receive Enter/Leave events.
+    ///         A view must be visible to receive Enter events (Leave events are always received).
     ///     </para>
     ///     <para>
     ///         This method calls <see cref="OnMouseLeave"/> to raise the <see cref="MouseLeave"/> event.
@@ -392,11 +392,6 @@ public partial class View // Mouse APIs
     /// <returns><see langword="true"/> if the event was handled, <see langword="false"/> otherwise. </returns>
     internal bool? NewMouseLeaveEvent (MouseEvent mouseEvent)
     {
-        if (!CanBeVisible (this))
-        {
-            return false;
-        }
-
         if (OnMouseLeave (mouseEvent))
         {
             return true;

+ 337 - 0
UnitTests/Application/Mouse/MouseEnterLeaveTests.cs

@@ -0,0 +1,337 @@
+namespace Terminal.Gui.ViewMouseTests;
+
+[Trait ("Category", "Input")]
+public class ApplicationMouseEnterLeaveTests
+{
+    private class TestView : View
+    {
+        public TestView ()
+        {
+            X = 1;
+            Y = 1;
+            Width = 1;
+            Height = 1;
+        }
+
+        public bool HandleOnEnter { get; }
+        public bool HandleOnLeave { get; }
+
+        public int OnMouseEnterCalled { get; private set; }
+        public int OnMouseLeaveCalled { get; private set; }
+
+        protected internal override bool? OnMouseEnter (MouseEvent mouseEvent)
+        {
+            OnMouseEnterCalled++;
+            mouseEvent.Handled = HandleOnEnter;
+
+            base.OnMouseEnter (mouseEvent);
+
+            return mouseEvent.Handled;
+        }
+
+        protected internal override bool OnMouseLeave (MouseEvent mouseEvent)
+        {
+            OnMouseLeaveCalled++;
+            mouseEvent.Handled = HandleOnLeave;
+
+            base.OnMouseLeave (mouseEvent);
+
+            return mouseEvent.Handled;
+        }
+    }
+
+    [Fact]
+    public void RaiseMouseEnterLeaveEvents_MouseEntersView_CallsOnMouseEnter ()
+    {
+        // Arrange
+        Application.Top = new () { Frame = new (0, 0, 10, 10) };
+        var view = new TestView ();
+        Application.Top.Add (view);
+        var mousePosition = new Point (1, 1);
+        List<View> currentViewsUnderMouse = new () { view };
+        var mouseEvent = new MouseEvent ()
+        {
+            Position = mousePosition,
+            ScreenPosition = mousePosition
+        };
+
+        Application._cachedViewsUnderMouse.Clear ();
+
+        try
+        {
+            // Act
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, currentViewsUnderMouse, mouseEvent);
+
+            // Assert
+            Assert.Equal (1, view.OnMouseEnterCalled);
+        }
+        finally
+        {
+            // Cleanup
+            Application.Top?.Dispose ();
+            Application.ResetState ();
+        }
+    }
+
+    [Fact]
+    public void RaiseMouseEnterLeaveEvents_MouseLeavesView_CallsOnMouseLeave ()
+    {
+        // Arrange
+        Application.Top = new () { Frame = new (0, 0, 10, 10) };
+        var view = new TestView ();
+        Application.Top.Add (view);
+        var mousePosition = new Point (0, 0);
+        List<View> currentViewsUnderMouse = new ();
+        var mouseEvent = new MouseEvent ();
+
+        Application._cachedViewsUnderMouse.Clear ();
+        Application._cachedViewsUnderMouse.Add (view);
+
+        try
+        {
+            // Act
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, currentViewsUnderMouse, mouseEvent);
+
+            // Assert
+            Assert.Equal (0, view.OnMouseEnterCalled);
+            Assert.Equal (1, view.OnMouseLeaveCalled);
+        }
+        finally
+        {
+            // Cleanup
+            Application.Top?.Dispose ();
+            Application.ResetState ();
+        }
+    }
+
+    [Fact]
+    public void RaiseMouseEnterLeaveEvents_MouseMovesBetweenAdjacentViews_CallsOnMouseEnterAndLeave ()
+    {
+        // Arrange
+        Application.Top = new () { Frame = new (0, 0, 10, 10) };
+        var view1 = new TestView (); // at 1,1 to 2,2
+        var view2 = new TestView () // at 2,2 to 3,3
+        {
+            X = 2,
+            Y = 2,
+        };
+        Application.Top.Add (view1);
+        Application.Top.Add (view2);
+
+
+
+        Application._cachedViewsUnderMouse.Clear ();
+
+        try
+        {
+            // Act
+            var mousePosition = new Point (0, 0);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (0, view1.OnMouseEnterCalled);
+            Assert.Equal (0, view1.OnMouseLeaveCalled);
+            Assert.Equal (0, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (1, 1);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (0, view1.OnMouseLeaveCalled);
+            Assert.Equal (0, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (2, 2);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+
+            // Act
+            mousePosition = new Point (3, 3);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (1, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (0, 0);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (1, view2.OnMouseLeaveCalled);
+        }
+        finally
+        {
+            // Cleanup
+            Application.Top?.Dispose ();
+            Application.ResetState ();
+        }
+    }
+
+    [Fact]
+    public void RaiseMouseEnterLeaveEvents_NoViewsUnderMouse_DoesNotCallOnMouseEnterOrLeave ()
+    {
+        // Arrange
+        Application.Top = new () { Frame = new (0, 0, 10, 10) };
+        var view = new TestView ();
+        Application.Top.Add (view);
+        var mousePosition = new Point (0, 0);
+        List<View> currentViewsUnderMouse = new ();
+        var mouseEvent = new MouseEvent ();
+
+        Application._cachedViewsUnderMouse.Clear ();
+
+        try
+        {
+            // Act
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, currentViewsUnderMouse, mouseEvent);
+
+            // Assert
+            Assert.Equal (0, view.OnMouseEnterCalled);
+            Assert.Equal (0, view.OnMouseLeaveCalled);
+        }
+        finally
+        {
+            // Cleanup
+            Application.Top?.Dispose ();
+            Application.ResetState ();
+        }
+    }
+
+
+    [Fact]
+    public void RaiseMouseEnterLeaveEvents_MouseMovesBetweenOverlappingViews_CallsOnMouseEnterAndLeave ()
+    {
+        // Arrange
+        Application.Top = new () { Frame = new (0, 0, 10, 10) };
+        var view1 = new TestView ()
+        {
+            Width = 2
+        }; // at 1,1 to 3,2
+        var view2 = new TestView () // at 2,2 to 4,3
+        {
+            Width = 2,
+            X = 2,
+            Y = 2,
+        };
+        Application.Top.Add (view1);
+        Application.Top.Add (view2);
+
+        Application._cachedViewsUnderMouse.Clear ();
+
+        try
+        {
+            // Act
+            var mousePosition = new Point (0, 0);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (0, view1.OnMouseEnterCalled);
+            Assert.Equal (0, view1.OnMouseLeaveCalled);
+            Assert.Equal (0, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (1, 1);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (0, view1.OnMouseLeaveCalled);
+            Assert.Equal (0, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (2, 2);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (0, view2.OnMouseLeaveCalled);
+
+
+            // Act
+            mousePosition = new Point (3, 3);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (1, view2.OnMouseLeaveCalled);
+
+            // Act
+            mousePosition = new Point (0, 0);
+            Application.RaiseMouseEnterLeaveEvents (mousePosition, View.GetViewsUnderMouse (mousePosition), new MouseEvent ()
+            {
+                Position = mousePosition,
+                ScreenPosition = mousePosition
+            });
+
+            // Assert
+            Assert.Equal (1, view1.OnMouseEnterCalled);
+            Assert.Equal (1, view1.OnMouseLeaveCalled);
+            Assert.Equal (1, view2.OnMouseEnterCalled);
+            Assert.Equal (1, view2.OnMouseLeaveCalled);
+        }
+        finally
+        {
+            // Cleanup
+            Application.Top?.Dispose ();
+            Application.ResetState ();
+        }
+    }
+}

+ 0 - 0
UnitTests/Application/MouseTests.cs → UnitTests/Application/Mouse/MouseTests.cs


+ 5 - 4
UnitTests/View/Mouse/MouseEnterLeaveTests.cs

@@ -160,7 +160,7 @@ public class MouseEnterLeaveTests
     }
 
     [Fact]
-    public void NewMouseLeaveEvent_ViewIsNotVisible_DoesNotCallOnMouseLeave ()
+    public void NewMouseLeaveEvent_ViewIsNotVisible_CallsOnMouseLeave ()
     {
         // Arrange
         var view = new TestView
@@ -175,7 +175,7 @@ public class MouseEnterLeaveTests
         bool? handled = view.NewMouseLeaveEvent (mouseEvent);
 
         // Assert
-        Assert.False (view.OnMouseLeaveCalled);
+        Assert.True (view.OnMouseLeaveCalled);
         Assert.False (handled);
         Assert.False (mouseEvent.Handled);
 
@@ -263,7 +263,8 @@ public class MouseEnterLeaveTests
         // Arrange
         var view = new TestView
         {
-            Enabled = true, Visible = true
+            Enabled = true, 
+            Visible = true
         };
 
         var mouseEvent = new MouseEvent ();
@@ -296,7 +297,7 @@ public class MouseEnterLeaveTests
         bool? handled = view.NewMouseLeaveEvent (mouseEvent);
 
         // Assert
-        Assert.False (view.MouseLeaveRaised);
+        Assert.True (view.MouseLeaveRaised);
         Assert.False (handled);
         Assert.False (mouseEvent.Handled);