From 309c9f7a4b9cc6d8ad376edc7c7e68e9f8716287 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 8 Jun 2017 00:40:11 +0200 Subject: [PATCH] Added some LayoutManager tests. Some passing, some failing. --- .../LayoutManagerTests.cs | 241 +++++++++++++++++- .../LayoutTestControl.cs | 29 +++ .../LayoutTestRoot.cs | 43 ++++ .../TestLayoutRoot.cs | 24 -- tests/Avalonia.UnitTests/TestRoot.cs | 2 +- 5 files changed, 307 insertions(+), 32 deletions(-) create mode 100644 tests/Avalonia.Layout.UnitTests/LayoutTestControl.cs create mode 100644 tests/Avalonia.Layout.UnitTests/LayoutTestRoot.cs delete mode 100644 tests/Avalonia.Layout.UnitTests/TestLayoutRoot.cs diff --git a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs index f67c5a353f..45e8803f16 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs @@ -2,25 +2,245 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Avalonia.Controls; +using Avalonia.UnitTests; +using System; using Xunit; +using System.Collections.Generic; namespace Avalonia.Layout.UnitTests { public class LayoutManagerTests { [Fact] - public void Invalidating_Child_Should_Remeasure_Parent() + public void Measures_And_Arranges_InvalidateMeasured_Control() { - var layoutManager = new LayoutManager(); + var target = new LayoutManager(); - using (AvaloniaLocator.EnterScope()) + using (Start(target)) { - AvaloniaLocator.CurrentMutable.Bind().ToConstant(layoutManager); + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + + target.ExecuteInitialLayoutPass(root); + control.Measured = control.Arranged = false; + + control.InvalidateMeasure(); + target.ExecuteLayoutPass(); + + Assert.True(control.Measured); + Assert.True(control.Arranged); + } + } + + [Fact] + public void Arranges_InvalidateArranged_Control() + { + var target = new LayoutManager(); + + using (Start(target)) + { + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + + target.ExecuteInitialLayoutPass(root); + control.Measured = control.Arranged = false; + + control.InvalidateArrange(); + target.ExecuteLayoutPass(); + + Assert.False(control.Measured); + Assert.True(control.Arranged); + } + } + + [Fact] + public void Measures_Parent_Of_Newly_Added_Control() + { + var target = new LayoutManager(); + + using (Start(target)) + { + var control = new LayoutTestControl(); + var root = new LayoutTestRoot(); + + target.ExecuteInitialLayoutPass(root); + root.Child = control; + root.Measured = root.Arranged = false; + + target.ExecuteLayoutPass(); + + Assert.True(root.Measured); + Assert.True(root.Arranged); + Assert.True(control.Measured); + Assert.True(control.Arranged); + } + } + + [Fact] + public void Measures_In_Correct_Order() + { + var target = new LayoutManager(); + + using (Start(target)) + { + LayoutTestControl control1; + LayoutTestControl control2; + var root = new LayoutTestRoot + { + Child = control1 = new LayoutTestControl + { + Child = control2 = new LayoutTestControl(), + } + }; + + + var order = new List(); + Size MeasureOverride(ILayoutable control, Size size) + { + order.Add(control); + return new Size(10, 10); + } + + root.DoMeasureOverride = MeasureOverride; + control1.DoMeasureOverride = MeasureOverride; + control2.DoMeasureOverride = MeasureOverride; + target.ExecuteInitialLayoutPass(root); + + control2.InvalidateMeasure(); + control1.InvalidateMeasure(); + root.InvalidateMeasure(); + + order.Clear(); + target.ExecuteLayoutPass(); + + Assert.Equal(new ILayoutable[] { root, control1, control2 }, order); + } + } + + [Fact] + public void Measures_Root_And_Grandparent_In_Correct_Order() + { + var target = new LayoutManager(); + + using (Start(target)) + { + LayoutTestControl control1; + LayoutTestControl control2; + var root = new LayoutTestRoot + { + Child = control1 = new LayoutTestControl + { + Child = control2 = new LayoutTestControl(), + } + }; + + + var order = new List(); + Size MeasureOverride(ILayoutable control, Size size) + { + order.Add(control); + return new Size(10, 10); + } + + root.DoMeasureOverride = MeasureOverride; + control1.DoMeasureOverride = MeasureOverride; + control2.DoMeasureOverride = MeasureOverride; + target.ExecuteInitialLayoutPass(root); + + control2.InvalidateMeasure(); + root.InvalidateMeasure(); + + order.Clear(); + target.ExecuteLayoutPass(); + + Assert.Equal(new ILayoutable[] { root, control2 }, order); + } + } + + [Fact] + public void Doesnt_Measure_Non_Invalidated_Root() + { + var target = new LayoutManager(); + + using (Start(target)) + { + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + + target.ExecuteInitialLayoutPass(root); + root.Measured = root.Arranged = false; + control.Measured = control.Arranged = false; + + control.InvalidateMeasure(); + target.ExecuteLayoutPass(); + + Assert.False(root.Measured); + Assert.False(root.Arranged); + Assert.True(control.Measured); + Assert.True(control.Arranged); + } + } + + [Fact] + public void Doesnt_Measure_Removed_Control() + { + var target = new LayoutManager(); + + using (Start(target)) + { + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + + target.ExecuteInitialLayoutPass(root); + control.Measured = control.Arranged = false; + + control.InvalidateMeasure(); + root.Child = null; + target.ExecuteLayoutPass(); + + Assert.False(control.Measured); + Assert.False(control.Arranged); + } + } + + [Fact] + public void Measures_Root_With_Infinity() + { + var target = new LayoutManager(); + + using (Start(target)) + { + var root = new LayoutTestRoot(); + var availableSize = default(Size); + + // Should not measure with this size. + root.MaxClientSize = new Size(123, 456); + + root.DoMeasureOverride = (_, s) => + { + availableSize = s; + return new Size(100, 100); + }; + + target.ExecuteInitialLayoutPass(root); + + Assert.Equal(Size.Infinity, availableSize); + } + } + + [Fact] + public void Invalidating_Child_Remeasures_Parent() + { + var target = new LayoutManager(); + + using (Start(target)) + { + AvaloniaLocator.CurrentMutable.Bind().ToConstant(target); Border border; StackPanel panel; - var root = new TestLayoutRoot + var root = new LayoutTestRoot { Child = panel = new StackPanel { @@ -31,15 +251,22 @@ namespace Avalonia.Layout.UnitTests } }; - layoutManager.ExecuteInitialLayoutPass(root); + target.ExecuteInitialLayoutPass(root); Assert.Equal(new Size(0, 0), root.DesiredSize); border.Width = 100; border.Height = 100; - layoutManager.ExecuteLayoutPass(); + target.ExecuteLayoutPass(); Assert.Equal(new Size(100, 100), panel.DesiredSize); } } + + private IDisposable Start(LayoutManager layoutManager) + { + var result = AvaloniaLocator.EnterScope(); + AvaloniaLocator.CurrentMutable.Bind().ToConstant(layoutManager); + return result; + } } } diff --git a/tests/Avalonia.Layout.UnitTests/LayoutTestControl.cs b/tests/Avalonia.Layout.UnitTests/LayoutTestControl.cs new file mode 100644 index 0000000000..f7f072eb1e --- /dev/null +++ b/tests/Avalonia.Layout.UnitTests/LayoutTestControl.cs @@ -0,0 +1,29 @@ +using System; +using Avalonia.Controls; + +namespace Avalonia.Layout.UnitTests +{ + internal class LayoutTestControl : Decorator + { + public bool Measured { get; set; } + public bool Arranged { get; set; } + public Func DoMeasureOverride { get; set; } + public Func DoArrangeOverride { get; set; } + + protected override Size MeasureOverride(Size availableSize) + { + Measured = true; + return DoMeasureOverride != null ? + DoMeasureOverride(this, availableSize) : + base.MeasureOverride(availableSize); + } + + protected override Size ArrangeOverride(Size finalSize) + { + Arranged = true; + return DoArrangeOverride != null ? + DoArrangeOverride(this, finalSize) : + base.ArrangeOverride(finalSize); + } + } +} diff --git a/tests/Avalonia.Layout.UnitTests/LayoutTestRoot.cs b/tests/Avalonia.Layout.UnitTests/LayoutTestRoot.cs new file mode 100644 index 0000000000..07476844e0 --- /dev/null +++ b/tests/Avalonia.Layout.UnitTests/LayoutTestRoot.cs @@ -0,0 +1,43 @@ +// 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; +using Avalonia.UnitTests; + +namespace Avalonia.Layout.UnitTests +{ + internal class LayoutTestRoot : TestRoot, ILayoutable + { + public bool Measured { get; set; } + public bool Arranged { get; set; } + public Func DoMeasureOverride { get; set; } + public Func DoArrangeOverride { get; set; } + + void ILayoutable.Measure(Size availableSize) + { + Measured = true; + Measure(availableSize); + } + + void ILayoutable.Arrange(Rect rect) + { + Arranged = true; + Arrange(rect); + } + + protected override Size MeasureOverride(Size availableSize) + { + return DoMeasureOverride != null ? + DoMeasureOverride(this, availableSize) : + base.MeasureOverride(availableSize); + } + + protected override Size ArrangeOverride(Size finalSize) + { + Arranged = true; + return DoArrangeOverride != null ? + DoArrangeOverride(this, finalSize) : + base.ArrangeOverride(finalSize); + } + } +} diff --git a/tests/Avalonia.Layout.UnitTests/TestLayoutRoot.cs b/tests/Avalonia.Layout.UnitTests/TestLayoutRoot.cs deleted file mode 100644 index fab1647c5d..0000000000 --- a/tests/Avalonia.Layout.UnitTests/TestLayoutRoot.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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 Avalonia.Controls; - -namespace Avalonia.Layout.UnitTests -{ - internal class TestLayoutRoot : Decorator, ILayoutRoot - { - public TestLayoutRoot() - { - ClientSize = new Size(500, 500); - } - - public Size ClientSize - { - get; - set; - } - - public Size MaxClientSize => Size.Infinity; - public double LayoutScaling => 1; - } -} diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs index 8a711c415e..399870aef9 100644 --- a/tests/Avalonia.UnitTests/TestRoot.cs +++ b/tests/Avalonia.UnitTests/TestRoot.cs @@ -43,7 +43,7 @@ namespace Avalonia.UnitTests public Size ClientSize => new Size(100, 100); - public Size MaxClientSize => Size.Infinity; + public Size MaxClientSize { get; set; } = Size.Infinity; public double LayoutScaling => 1;