Răsfoiți Sursa

add some more layout manager tests for potential issues with infinity loop and proper work

Andrey Kunchev 6 ani în urmă
părinte
comite
d53dbe9416
1 a modificat fișierele cu 110 adăugiri și 9 ștergeri
  1. 110 9
      tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs

+ 110 - 9
tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs

@@ -1,11 +1,10 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System.Collections.Generic;
+using System.Linq;
 using Avalonia.Controls;
-using Avalonia.UnitTests;
-using System;
 using Xunit;
-using System.Collections.Generic;
 
 namespace Avalonia.Layout.UnitTests
 {
@@ -74,7 +73,6 @@ namespace Avalonia.Layout.UnitTests
                 }
             };
 
-
             var order = new List<ILayoutable>();
             Size MeasureOverride(ILayoutable control, Size size)
             {
@@ -110,7 +108,6 @@ namespace Avalonia.Layout.UnitTests
                 }
             };
 
-
             var order = new List<ILayoutable>();
             Size MeasureOverride(ILayoutable control, Size size)
             {
@@ -196,9 +193,9 @@ namespace Avalonia.Layout.UnitTests
                 Width = 100,
                 Height = 100,
             };
- 
+
             var arrangeSize = default(Size);
- 
+
             root.DoArrangeOverride = (_, s) =>
             {
                 arrangeSize = s;
@@ -207,7 +204,7 @@ namespace Avalonia.Layout.UnitTests
 
             root.LayoutManager.ExecuteInitialLayoutPass(root);
             Assert.Equal(new Size(100, 100), arrangeSize);
- 
+
             root.Width = 120;
 
             root.LayoutManager.ExecuteLayoutPass();
@@ -238,7 +235,111 @@ namespace Avalonia.Layout.UnitTests
             border.Height = 100;
 
             root.LayoutManager.ExecuteLayoutPass();
-            Assert.Equal(new Size(100, 100), panel.DesiredSize);             
+            Assert.Equal(new Size(100, 100), panel.DesiredSize);
+        }
+
+        [Fact]
+        public void LayoutManager_Should_Prevent_Infinity_Loop_On_Measure()
+        {
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
+
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            control.Measured = false;
+
+            int cnt = 0;
+            int maxcnt = 100;
+            control.DoMeasureOverride = (l, s) =>
+            {
+                //emulate a problem in the logic of a control that triggers
+                //invalidate measure during measure
+                //it can lead to infinity loop in layoutmanager
+                if (++cnt < maxcnt)
+                {
+                    control.InvalidateMeasure();
+                }
+
+                return new Size(100, 100);
+            };
+
+            control.InvalidateMeasure();
+
+            root.LayoutManager.ExecuteLayoutPass();
+
+            Assert.True(cnt < 100);
+        }
+
+        [Fact]
+        public void LayoutManager_Should_Prevent_Infinity_Loop_On_Arrange()
+        {
+            var control = new LayoutTestControl();
+            var root = new LayoutTestRoot { Child = control };
+
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+            control.Arranged = false;
+
+            int cnt = 0;
+            int maxcnt = 100;
+            control.DoArrangeOverride = (l, s) =>
+            {
+                //emulate a problem in the logic of a control that triggers
+                //invalidate measure during arrange
+                //it can lead to infinity loop in layoutmanager
+                if (++cnt < maxcnt)
+                {
+                    control.InvalidateArrange();
+                }
+
+                return new Size(100, 100);
+            };
+
+            control.InvalidateArrange();
+
+            root.LayoutManager.ExecuteLayoutPass();
+
+            Assert.True(cnt < 100);
+        }
+
+        [Fact]
+        public void LayoutManager_Should_Properly_Arrange_Visuals_Even_There_Are_Issues_With_Previous_Arranged()
+        {
+            var nonArrageableTargets = Enumerable.Range(1, 10).Select(_ => new LayoutTestControl()).ToArray();
+            var targets = Enumerable.Range(1, 10).Select(_ => new LayoutTestControl()).ToArray();
+
+            StackPanel panel;
+
+            var root = new LayoutTestRoot
+            {
+                Child = panel = new StackPanel()
+            };
+
+            panel.Children.AddRange(nonArrageableTargets);
+            panel.Children.AddRange(targets);
+
+            root.LayoutManager.ExecuteInitialLayoutPass(root);
+
+            foreach (var c in panel.Children.OfType<LayoutTestControl>())
+            {
+                c.Measured = c.Arranged = false;
+                c.InvalidateMeasure();
+            }
+
+            foreach (var c in nonArrageableTargets)
+            {
+                c.DoArrangeOverride = (l, s) =>
+                {
+                    //emulate a problem in the logic of a control that triggers
+                    //invalidate measure during arrange
+                    c.InvalidateMeasure();
+                    return new Size(100, 100);
+                };
+            }
+
+            root.LayoutManager.ExecuteLayoutPass();
+
+            //altough nonArrageableTargets has rubbish logic and can't be measured/arranged properly
+            //layoutmanager should process properly other visuals
+            Assert.All(targets, c => Assert.True(c.Arranged));
         }
     }
 }