Browse Source

Added failing test for #3784.

Had to refactor the `MockWindowingPlatform` a bit.
Steven Kirk 5 years ago
parent
commit
af950096cc

+ 4 - 3
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@@ -209,16 +209,17 @@ namespace Avalonia.Controls.UnitTests
             screenImpl.Setup(x => x.ScreenCount).Returns(1);
             screenImpl.Setup(X => X.AllScreens).Returns( new[] { new Screen(1, screen, screen, true) });
 
-            popupImpl = MockWindowingPlatform.CreatePopupMock();
+            var windowImpl = MockWindowingPlatform.CreateWindowMock();
+            popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object);
             popupImpl.SetupGet(x => x.Scaling).Returns(1);
+            windowImpl.Setup(x => x.CreatePopup()).Returns(popupImpl.Object);
 
-            var windowImpl = MockWindowingPlatform.CreateWindowMock(() => popupImpl.Object);
             windowImpl.Setup(x => x.Screen).Returns(screenImpl.Object);
 
             var services = TestServices.StyledWindow.With(
                                         inputManager: new InputManager(),
                                         windowImpl: windowImpl.Object,
-                                        windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object, () => popupImpl.Object));
+                                        windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object, x => popupImpl.Object));
 
             return UnitTestApplication.Start(services);
         }

+ 80 - 2
tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs

@@ -4,6 +4,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.LogicalTree;
+using Avalonia.Platform;
 using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Avalonia.VisualTree;
@@ -172,9 +173,75 @@ namespace Avalonia.Controls.UnitTests.Primitives
             }
         }
 
-        private PopupRoot CreateTarget(TopLevel popupParent)
+        [Fact]
+        public void Child_Should_Be_Measured_With_Infinity()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var child = new ChildControl();
+                var window = new Window();
+                var target = CreateTarget(window);
+                
+                target.Content = child;
+                target.Show();
+
+                Assert.Equal(Size.Infinity, child.MeasureSize);
+            }
+        }
+
+        [Fact]
+        public void Child_Should_Be_Measured_With_Width_Height_When_Set()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var child = new ChildControl();
+                var window = new Window();
+                var target = CreateTarget(window);
+
+                target.Width = 500;
+                target.Height = 600;
+                target.Content = child;
+                target.Show();
+
+                Assert.Equal(new Size(500, 600), child.MeasureSize);
+            }
+        }
+
+        [Fact]
+        public void Should_Not_Have_Offset_On_Bounds_When_Content_Larger_Than_Max_Window_Size()
+        {
+            // Issue #3784.
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var window = new Window();
+                var popupImpl = MockWindowingPlatform.CreatePopupMock(window.PlatformImpl);
+
+                popupImpl.Setup(x => x.ClientSize).Returns(new Size(400, 480));
+
+                var child = new Canvas
+                {
+                    Width = 400,
+                    Height = 800,
+                };
+
+                var target = CreateTarget(window, popupImpl.Object);
+                target.Content = child;
+
+                target.Show();
+
+                Assert.Equal(new Size(400, 480), target.Bounds.Size);
+
+                // Issue #3784 causes this to be (0, 160) which makes no sense as Window has no
+                // parent control to be offset against.
+                Assert.Equal(new Point(0, 0), target.Bounds.Position);
+            }
+        }
+
+        private PopupRoot CreateTarget(TopLevel popupParent, IPopupImpl impl = null)
         {
-            var result = new PopupRoot(popupParent, popupParent.PlatformImpl.CreatePopup())
+            impl ??= popupParent.PlatformImpl.CreatePopup();
+
+            var result = new PopupRoot(popupParent, impl)
             {
                 Template = new FuncControlTemplate<PopupRoot>((parent, scope) =>
                     new ContentPresenter
@@ -217,5 +284,16 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 Popup = (Popup)this.GetVisualChildren().Single();
             }
         }
+
+        private class ChildControl : Control
+        {
+            public Size MeasureSize { get; private set; }
+
+            protected override Size MeasureOverride(Size availableSize)
+            {
+                MeasureSize = availableSize;
+                return base.MeasureOverride(availableSize);
+            }
+        }
     }
 }

+ 2 - 2
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@@ -355,11 +355,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
         {
             return UnitTestApplication.Start(TestServices.StyledWindow.With(windowingPlatform:
                 new MockWindowingPlatform(null,
-                    () =>
+                    x =>
                     {
                         if(UsePopupHost)
                             return null;
-                        return MockWindowingPlatform.CreatePopupMock().Object;
+                        return MockWindowingPlatform.CreatePopupMock(x).Object;
                     })));
         }
 

+ 118 - 0
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
+using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.UnitTests;
@@ -375,6 +376,123 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
+        [Fact]
+        public void Should_Not_Have_Offset_On_Bounds_When_Content_Larger_Than_Max_Window_Size()
+        {
+            // Issue #3784.
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var windowImpl = MockWindowingPlatform.CreateWindowMock();
+                var clientSize = new Size(200, 200);
+                var maxClientSize = new Size(480, 480);
+
+                windowImpl.Setup(x => x.Resize(It.IsAny<Size>())).Callback<Size>(size =>
+                {
+                    clientSize = size.Constrain(maxClientSize);
+                    windowImpl.Object.Resized?.Invoke(clientSize);
+                });
+
+                windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize);
+
+                var child = new Canvas
+                {
+                    Width = 400,
+                    Height = 800,
+                };
+                var target = new Window(windowImpl.Object)
+                {
+                    SizeToContent = SizeToContent.WidthAndHeight,
+                    Content = child
+                };
+
+                target.Show();
+
+                Assert.Equal(new Size(400, 480), target.Bounds.Size);
+
+                // Issue #3784 causes this to be (0, 160) which makes no sense as Window has no
+                // parent control to be offset against.
+                Assert.Equal(new Point(0, 0), target.Bounds.Position);
+            }
+        }
+
+        [Fact]
+        public void Width_Height_Should_Not_Be_NaN_After_Show_With_SizeToContent_WidthAndHeight()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var child = new Canvas
+                {
+                    Width = 400,
+                    Height = 800,
+                };
+
+                var target = new Window()
+                {
+                    SizeToContent = SizeToContent.WidthAndHeight,
+                    Content = child
+                };
+
+                target.Show();
+
+                Assert.Equal(400, target.Width);
+                Assert.Equal(800, target.Height);
+            }
+        }
+
+        [Fact]
+        public void SizeToContent_Should_Not_Be_Lost_On_Show()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var child = new Canvas
+                {
+                    Width = 400,
+                    Height = 800,
+                };
+
+                var target = new Window()
+                {
+                    SizeToContent = SizeToContent.WidthAndHeight,
+                    Content = child
+                };
+
+                target.Show();
+
+                Assert.Equal(SizeToContent.WidthAndHeight, target.SizeToContent);
+            }
+        }
+
+        [Fact]
+        public void Width_Height_Should_Be_Updated_When_SizeToContent_Is_WidthAndHeight()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var child = new Canvas
+                {
+                    Width = 400,
+                    Height = 800,
+                };
+
+                var target = new Window()
+                {
+                    SizeToContent = SizeToContent.WidthAndHeight,
+                    Content = child
+                };
+
+                target.Show();
+
+                Assert.Equal(400, target.Width);
+                Assert.Equal(800, target.Height);
+
+                child.Width = 410;
+                target.LayoutManager.ExecuteLayoutPass();
+
+                Assert.Equal(410, target.Width);
+                Assert.Equal(800, target.Height);
+                Assert.Equal(SizeToContent.WidthAndHeight, target.SizeToContent);
+            }
+        }
+
         private IWindowImpl CreateImpl(Mock<IRenderer> renderer)
         {
             return Mock.Of<IWindowImpl>(x =>

+ 82 - 29
tests/Avalonia.UnitTests/MockWindowingPlatform.cs

@@ -8,65 +8,118 @@ namespace Avalonia.UnitTests
 {
     public class MockWindowingPlatform : IWindowingPlatform
     {
+        private static readonly Size s_screenSize = new Size(1280, 1024);
         private readonly Func<IWindowImpl> _windowImpl;
-        private readonly Func<IPopupImpl> _popupImpl;
+        private readonly Func<IWindowBaseImpl, IPopupImpl> _popupImpl;
 
-        public MockWindowingPlatform(Func<IWindowImpl> windowImpl = null, Func<IPopupImpl> popupImpl = null )
+        public MockWindowingPlatform(
+            Func<IWindowImpl> windowImpl = null,
+            Func<IWindowBaseImpl, IPopupImpl> popupImpl = null )
         {
             _windowImpl = windowImpl;
             _popupImpl = popupImpl;
         }
 
-        public static Mock<IWindowImpl> CreateWindowMock(Func<IPopupImpl> popupImpl = null)
+        public static Mock<IWindowImpl> CreateWindowMock()
         {
-            var win = Mock.Of<IWindowImpl>(x => x.Scaling == 1);
-            var mock = Mock.Get(win);
-            mock.Setup(x => x.Show()).Callback(() =>
+            var windowImpl = new Mock<IWindowImpl>();
+            var position = new PixelPoint();
+            var clientSize = new Size(800, 600);
+
+            windowImpl.SetupAllProperties();
+            windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize);
+            windowImpl.Setup(x => x.Scaling).Returns(1);
+            windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object);
+            windowImpl.Setup(x => x.Position).Returns(() => position);
+            SetupToplevel(windowImpl);
+
+            windowImpl.Setup(x => x.CreatePopup()).Returns(() =>
             {
-                mock.Object.Activated?.Invoke();
+                return CreatePopupMock(windowImpl.Object).Object;
             });
-            mock.Setup(x => x.CreatePopup()).Returns(() =>
+
+            windowImpl.Setup(x => x.Dispose()).Callback(() =>
             {
-                if (popupImpl != null)
-                    return popupImpl();
-                return CreatePopupMock().Object;
+                windowImpl.Object.Closed?.Invoke();
+            });
+
+            windowImpl.Setup(x => x.Move(It.IsAny<PixelPoint>())).Callback<PixelPoint>(x =>
+            {
+                position = x;
+                windowImpl.Object.PositionChanged?.Invoke(x);
+            });
 
+            windowImpl.Setup(x => x.Resize(It.IsAny<Size>())).Callback<Size>(x =>
+            {
+                clientSize = x.Constrain(s_screenSize);
+                windowImpl.Object.Resized?.Invoke(clientSize);
             });
-            mock.Setup(x => x.Dispose()).Callback(() =>
+
+            windowImpl.Setup(x => x.Show()).Callback(() =>
             {
-                mock.Object.Closed?.Invoke();
+                windowImpl.Object.Activated?.Invoke();
             });
-            PixelPoint pos = default;
-            mock.SetupGet(x => x.Position).Returns(() => pos);
-            mock.Setup(x => x.Move(It.IsAny<PixelPoint>())).Callback(new Action<PixelPoint>(np => pos = np));
-            SetupToplevel(mock);
-            return mock;
+
+            return windowImpl;
         }
 
-        static void SetupToplevel<T>(Mock<T> mock) where T : class, ITopLevelImpl
+        public static Mock<IPopupImpl> CreatePopupMock(IWindowBaseImpl parent)
         {
-            mock.SetupGet(x => x.MouseDevice).Returns(new MouseDevice());
+            var popupImpl = new Mock<IPopupImpl>();
+
+            var positionerHelper = new ManagedPopupPositionerPopupImplHelper(parent, (pos, size, scale) =>
+            {
+                popupImpl.Object.PositionChanged?.Invoke(pos);
+                popupImpl.Object.Resized?.Invoke(size);
+            });
+            
+            var positioner = new ManagedPopupPositioner(positionerHelper);
+
+            popupImpl.Setup(x => x.Scaling).Returns(1);
+            popupImpl.Setup(x => x.PopupPositioner).Returns(positioner);
+            
+            SetupToplevel(popupImpl);
+            
+            return popupImpl;
         }
 
-        public static Mock<IPopupImpl> CreatePopupMock()
+        public static Mock<IScreenImpl> CreateScreenMock()
         {
-            var positioner = Mock.Of<IPopupPositioner>();
-            var popup = Mock.Of<IPopupImpl>(x => x.Scaling == 1);
-            var mock = Mock.Get(popup);
-            mock.SetupGet(x => x.PopupPositioner).Returns(positioner);
-            SetupToplevel(mock);
-            
-            return mock;
+            var screenImpl = new Mock<IScreenImpl>();
+            var bounds = new PixelRect(0, 0, (int)s_screenSize.Width, (int)s_screenSize.Height);
+            var screen = new Screen(96, bounds, bounds, true);
+            screenImpl.Setup(x => x.AllScreens).Returns(new[] { screen });
+            screenImpl.Setup(x => x.ScreenCount).Returns(1);
+            return screenImpl;
         }
 
         public IWindowImpl CreateWindow()
         {
-            return _windowImpl?.Invoke() ?? CreateWindowMock(_popupImpl).Object;
+            if (_windowImpl is object)
+            {
+                return _windowImpl();
+            }
+            else
+            {
+                var mock = CreateWindowMock();
+
+                if (_popupImpl is object)
+                {
+                    mock.Setup(x => x.CreatePopup()).Returns(() => _popupImpl(mock.Object));
+                }
+
+                return mock.Object;
+            }
         }
 
         public IEmbeddableWindowImpl CreateEmbeddableWindow()
         {
             throw new NotImplementedException();
         }
+
+        private static void SetupToplevel<T>(Mock<T> mock) where T : class, ITopLevelImpl
+        {
+            mock.SetupGet(x => x.MouseDevice).Returns(new MouseDevice());
+        }
     }
 }