From 94b6f133ea30f1fb6661403d5f46daa4ea45265d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 12 Oct 2020 17:30:36 +0200 Subject: [PATCH 1/9] Added failing test for #4822. --- .../Shapes/PathTests.cs | 22 ++++++++++++++++++- .../MockPlatformRenderInterface.cs | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs index 88c64e76cc..2a0bcc8d39 100644 --- a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs @@ -1,4 +1,5 @@ -using Avalonia.Controls.Shapes; +using System.Runtime.InteropServices; +using Avalonia.Controls.Shapes; using Avalonia.Media; using Avalonia.UnitTests; using Xunit; @@ -34,5 +35,24 @@ namespace Avalonia.Controls.UnitTests.Shapes root.Child = null; } + + [Fact] + public void Arrange_Without_Measure_Updates_RenderedGeometry_Transform() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 100) }, + Stretch = Stretch.Fill, + }; + + target.Measure(new Size(200, 200)); + target.Arrange(new Rect(0, 0, 200, 200)); + Assert.Equal(Matrix.CreateScale(2, 2), target.RenderedGeometry.Transform.Value); + + target.Arrange(new Rect(0, 0, 300, 300)); + Assert.Equal(Matrix.CreateScale(3, 3), target.RenderedGeometry.Transform.Value); + } } } diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index 08df23cbe1..e73a76357a 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -34,7 +34,7 @@ namespace Avalonia.UnitTests public IGeometryImpl CreateRectangleGeometry(Rect rect) { - return Mock.Of(); + return Mock.Of(x => x.Bounds == rect); } public IRenderTarget CreateRenderTarget(IEnumerable surfaces) From 93f215d8eaca8fa1dd9f04fb562055f338afae02 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 16:47:50 +0200 Subject: [PATCH 2/9] More tests for #4822. Tested WPF's `Path` to confirm expected results: https://github.com/wieslawsoltes/WpfUnitTests --- .../Shapes/PathTests.cs | 108 +++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs index 2a0bcc8d39..a10a03a5ae 100644 --- a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs @@ -1,5 +1,4 @@ -using System.Runtime.InteropServices; -using Avalonia.Controls.Shapes; +using Avalonia.Controls.Shapes; using Avalonia.Media; using Avalonia.UnitTests; using Xunit; @@ -36,6 +35,111 @@ namespace Avalonia.Controls.UnitTests.Shapes root.Child = null; } + [Theory] + [InlineData(Stretch.None, 100, 200)] + [InlineData(Stretch.Fill, 500, 500)] + [InlineData(Stretch.Uniform, 250, 500)] + [InlineData(Stretch.UniformToFill, 500, 500)] + public void Calculates_Correct_DesiredSize_For_Finite_Bounds(Stretch stretch, double expectedWidth, double expectedHeight) + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path() + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 200) }, + Stretch = stretch, + }; + + target.Measure(new Size(500, 500)); + + Assert.Equal(new Size(expectedWidth, expectedHeight), target.DesiredSize); + } + + [Theory] + [InlineData(Stretch.None)] + [InlineData(Stretch.Fill)] + [InlineData(Stretch.Uniform)] + [InlineData(Stretch.UniformToFill)] + public void Calculates_Correct_DesiredSize_For_Infinite_Bounds(Stretch stretch) + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path() + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 200) }, + Stretch = stretch, + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + Assert.Equal(new Size(100, 200), target.DesiredSize); + } + + [Fact] + public void Measure_Does_Not_Update_RenderedGeometry_Transform() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 200) }, + Stretch = Stretch.Fill, + }; + + target.Measure(new Size(500, 500)); + + Assert.Null(target.RenderedGeometry.Transform); + } + + [Theory] + [InlineData(Stretch.None, 1, 1)] + [InlineData(Stretch.Fill, 5, 2.5)] + [InlineData(Stretch.Uniform, 2.5, 2.5)] + [InlineData(Stretch.UniformToFill, 5, 5)] + public void Arrange_Updates_RenderedGeometry_Transform(Stretch stretch, double expectedScaleX, double expectedScaleY) + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 200) }, + Stretch = stretch, + }; + + target.Measure(new Size(500, 500)); + target.Arrange(new Rect(0, 0, 500, 500)); + + if (expectedScaleX == 1 && expectedScaleY == 1) + { + Assert.Null(target.RenderedGeometry.Transform); + } + else + { + Assert.Equal(Matrix.CreateScale(expectedScaleX, expectedScaleY), target.RenderedGeometry.Transform.Value); + } + } + + [Fact] + public void Measure_Without_Arrange_Does_Not_Clear_RenderedGeometry_Transform() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Path + { + Data = new RectangleGeometry { Rect = new Rect(0, 0, 100, 100) }, + Stretch = Stretch.Fill, + }; + + target.Measure(new Size(200, 200)); + target.Arrange(new Rect(0, 0, 200, 200)); + + Assert.Equal(Matrix.CreateScale(2, 2), target.RenderedGeometry.Transform.Value); + + target.Measure(new Size(300, 300)); + + Assert.Equal(Matrix.CreateScale(2, 2), target.RenderedGeometry.Transform.Value); + } + [Fact] public void Arrange_Without_Measure_Updates_RenderedGeometry_Transform() { From beada97aabaf46f44564f4bcdcfe2100c1421ddc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 16:48:06 +0200 Subject: [PATCH 3/9] Set RenderedGeometry.Transform on arrange. Fixes #4822 but breaks a bunch of other tests. --- src/Avalonia.Controls/Shapes/Shape.cs | 39 +++------------------------ 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index 7d1525afc4..67a7d48c61 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -248,52 +248,21 @@ namespace Avalonia.Controls.Shapes protected override Size MeasureOverride(Size availableSize) { - bool deferCalculateTransform; - switch (Stretch) + if (DefiningGeometry is null) { - case Stretch.Fill: - case Stretch.UniformToFill: - deferCalculateTransform = double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height); - break; - case Stretch.Uniform: - deferCalculateTransform = double.IsInfinity(availableSize.Width) && double.IsInfinity(availableSize.Height); - break; - case Stretch.None: - default: - deferCalculateTransform = false; - break; + return default; } - if (deferCalculateTransform) - { - _calculateTransformOnArrange = true; - return DefiningGeometry?.Bounds.Size ?? Size.Empty; - } - else - { - _calculateTransformOnArrange = false; - return CalculateShapeSizeAndSetTransform(availableSize); - } + return CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch).Item1; } protected override Size ArrangeOverride(Size finalSize) - { - if (_calculateTransformOnArrange) - { - _calculateTransformOnArrange = false; - CalculateShapeSizeAndSetTransform(finalSize); - } - - return finalSize; - } - - private Size CalculateShapeSizeAndSetTransform(Size availableSize) { if (DefiningGeometry != null) { // This should probably use GetRenderBounds(strokeThickness) but then the calculations // will multiply the stroke thickness as well, which isn't correct. - var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch); + var (size, transform) = CalculateSizeAndTransform(finalSize, DefiningGeometry.Bounds, Stretch); if (_transform != transform) { From 9f8f4b224f188d2cf48d9a613291b3dbb51dcc04 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 17:42:42 +0200 Subject: [PATCH 4/9] Provide a RenderInterface for controls which use shapes. --- tests/Avalonia.Controls.UnitTests/CanvasTests.cs | 9 +++++++++ .../LayoutTransformControlTests.cs | 15 +++++++++++++++ .../RelativePanelTests.cs | 6 ++++++ tests/Avalonia.Controls.UnitTests/ViewboxTests.cs | 13 +++++++++++++ 4 files changed, 43 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/CanvasTests.cs b/tests/Avalonia.Controls.UnitTests/CanvasTests.cs index da1698330f..11a349f53e 100644 --- a/tests/Avalonia.Controls.UnitTests/CanvasTests.cs +++ b/tests/Avalonia.Controls.UnitTests/CanvasTests.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Controls.Shapes; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Controls.UnitTests @@ -9,6 +10,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Left_Property_Should_Work() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + Rectangle rect; var target = new Canvas { @@ -34,6 +37,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Top_Property_Should_Work() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + Rectangle rect; var target = new Canvas { @@ -59,6 +64,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Right_Property_Should_Work() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + Rectangle rect; var target = new Canvas { @@ -84,6 +91,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Bottom_Property_Should_Work() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + Rectangle rect; var target = new Canvas { diff --git a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs index 13c946b549..60139c2881 100644 --- a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs @@ -1,5 +1,6 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Controls.UnitTests @@ -171,6 +172,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Generate_RotateTransform_90_degrees() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, 25, @@ -193,6 +196,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Generate_RotateTransform_minus_90_degrees() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, 25, @@ -215,6 +220,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Generate_ScaleTransform_x2() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, 50, @@ -236,6 +243,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Generate_SkewTransform_45_degrees() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, 100, @@ -258,6 +267,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Should_Generate_SkewTransform_minus_45_degrees() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, 100, @@ -279,6 +290,8 @@ namespace Avalonia.Controls.UnitTests private static void TransformMeasureSizeTest(Size size, Transform transform, Size expectedSize) { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( size.Width, size.Height, @@ -292,6 +305,8 @@ namespace Avalonia.Controls.UnitTests private static void TransformRootBoundsTest(Size size, Transform transform, Rect expectedBounds) { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(size.Width, size.Height, transform); Rect outBounds = lt.TransformRoot.Bounds; diff --git a/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs b/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs index 6e171a58e7..6b2f05c923 100644 --- a/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/RelativePanelTests.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Shapes; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Controls.UnitTests @@ -8,6 +9,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Lays_Out_1_Child_Next_the_other() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); var rect1 = new Rectangle { Height = 20, Width = 20 }; var rect2 = new Rectangle { Height = 20, Width = 20 }; @@ -34,6 +36,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Lays_Out_1_Child_Below_the_other() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); var rect1 = new Rectangle { Height = 20, Width = 20 }; var rect2 = new Rectangle { Height = 20, Width = 20 }; @@ -60,6 +63,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void RelativePanel_Can_Center() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); var rect1 = new Rectangle { Height = 20, Width = 20 }; var rect2 = new Rectangle { Height = 20, Width = 20 }; @@ -86,6 +90,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void LeftOf_Measures_Correctly() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); var rect1 = new Rectangle { Height = 20, Width = 20 }; var rect2 = new Rectangle { Height = 20, Width = 20 }; @@ -111,6 +116,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Above_Measures_Correctly() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); var rect1 = new Rectangle { Height = 20, Width = 20 }; var rect2 = new Rectangle { Height = 20, Width = 20 }; diff --git a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs index ad0f318d2f..e005bafbf9 100644 --- a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs @@ -1,5 +1,6 @@ using Avalonia.Controls.Shapes; using Avalonia.Media; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Controls.UnitTests @@ -9,6 +10,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_Uniform_Child() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(200, 200)); @@ -25,6 +28,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_None_Child() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Stretch = Stretch.None, Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(200, 200)); @@ -41,6 +46,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_Fill_Child() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Stretch = Stretch.Fill, Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(200, 200)); @@ -57,6 +64,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_UniformToFill_Child() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Stretch = Stretch.UniformToFill, Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(200, 200)); @@ -73,6 +82,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_Uniform_Child_With_Unrestricted_Width() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(double.PositiveInfinity, 200)); @@ -89,6 +100,8 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Viewbox_Stretch_Uniform_Child_With_Unrestricted_Height() { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + var target = new Viewbox() { Child = new Rectangle() { Width = 100, Height = 50 } }; target.Measure(new Size(200, double.PositiveInfinity)); From 10b6cfc0117427bda643b4ba9716df7dfa52e495 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 17:43:24 +0200 Subject: [PATCH 5/9] Reserve all of arrange rect. --- src/Avalonia.Controls/Shapes/Shape.cs | 3 +-- .../Shapes/PathTests.cs | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index 67a7d48c61..28206a398a 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -62,7 +62,6 @@ namespace Avalonia.Controls.Shapes private Matrix _transform = Matrix.Identity; private Geometry? _definingGeometry; private Geometry? _renderedGeometry; - private bool _calculateTransformOnArrange; static Shape() { @@ -270,7 +269,7 @@ namespace Avalonia.Controls.Shapes _renderedGeometry = null; } - return size; + return finalSize; } return Size.Empty; diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs index a10a03a5ae..8b8656a76b 100644 --- a/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs @@ -119,6 +119,26 @@ namespace Avalonia.Controls.UnitTests.Shapes } } + [Fact] + public void Arrange_Reserves_All_Of_Arrange_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + RectangleGeometry geometry; + var target = new Path + { + Data = geometry = new RectangleGeometry { Rect = new Rect(0, 0, 100, 200) }, + Stretch = Stretch.Uniform, + }; + + target.Measure(new Size(400, 400)); + target.Arrange(new Rect(0, 0, 400, 400)); + + Assert.Equal(new Rect(0, 0, 100, 200), geometry.Rect); + Assert.Equal(Matrix.CreateScale(2, 2), target.RenderedGeometry.Transform.Value); + Assert.Equal(new Rect(0, 0, 400, 400), target.Bounds); + } + [Fact] public void Measure_Without_Arrange_Does_Not_Clear_RenderedGeometry_Transform() { From 67215a85904eb250e979a905a3728c0fffff2a8c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 18:07:14 +0200 Subject: [PATCH 6/9] Removed outdated tests. --- .../ShapeLayoutTests.cs | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 tests/Avalonia.Layout.UnitTests/ShapeLayoutTests.cs diff --git a/tests/Avalonia.Layout.UnitTests/ShapeLayoutTests.cs b/tests/Avalonia.Layout.UnitTests/ShapeLayoutTests.cs deleted file mode 100644 index 2ccd6fb04c..0000000000 --- a/tests/Avalonia.Layout.UnitTests/ShapeLayoutTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System.Collections.Generic; -using Avalonia.Controls; -using Avalonia.Controls.Shapes; -using Avalonia.Media; -using Avalonia.Platform; -using Avalonia.UnitTests; -using Xunit; - -namespace Avalonia.Layout.UnitTests - -{ - public class ShapeLayoutTests : TestWithServicesBase - { - - public ShapeLayoutTests() - { - AvaloniaLocator.CurrentMutable - .Bind().ToSingleton(); - } - - [Fact] - public void Shape_Transformation_Calculation_Should_Be_Deferred_To_Arrange_When_Strech_Is_Fill_And_Aviable_Size_Is_Infinite() - { - var shape = new Polygon() - { - Points = new List - { - new Point(0, 0), - new Point(10, 5), - new Point(0, 10) - }, - Stretch = Stretch.Fill - }; - - var availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity); - shape.Measure(availableSize); - Geometry postMeasureGeometry = shape.RenderedGeometry; - Transform postMeasureTransform = postMeasureGeometry.Transform; - - var finalSize = new Size(100, 50); - var finalRect = new Rect(finalSize); - shape.Arrange(finalRect); - - Geometry postArrangeGeometry = shape.RenderedGeometry; - Transform postArrangeTransform = postArrangeGeometry.Transform; - - Assert.NotEqual(postMeasureGeometry, postArrangeGeometry); - Assert.NotEqual(postMeasureTransform, postArrangeTransform); - Assert.Equal(finalSize, shape.Bounds.Size); - } - - [Fact] - public void Shape_Transformation_Calculation_Should_Not_Be_Deferred_To_Arrange_When_Strech_Is_Fill_And_Aviable_Size_Is_Finite() - { - var shape = new Polygon() - { - Points = new List - { - new Point(0, 0), - new Point(10, 5), - new Point(0, 10) - }, - Stretch = Stretch.Fill - }; - - var availableSize = new Size(100, 50); - shape.Measure(availableSize); - Geometry postMeasureGeometry = shape.RenderedGeometry; - Transform postMeasureTransform = postMeasureGeometry.Transform; - - var finalRect = new Rect(availableSize); - shape.Arrange(finalRect); - - Geometry postArrangeGeometry = shape.RenderedGeometry; - Transform postArrangeTransform = postArrangeGeometry.Transform; - - Assert.Equal(postMeasureGeometry, postArrangeGeometry); - Assert.Equal(postMeasureTransform, postArrangeTransform); - Assert.Equal(availableSize, shape.Bounds.Size); - } - - [Fact] - public void Shape_Transformation_Calculation_Should_Not_Be_Deferred_To_Arrange_When_Strech_Is_None() - { - var shape = new Polygon() - { - Points = new List - { - new Point(0, 0), - new Point(10, 5), - new Point(0, 10) - }, - Stretch = Stretch.None - }; - - var availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity); - shape.Measure(availableSize); - Geometry postMeasureGeometry = shape.RenderedGeometry; - Transform postMeasureTransform = postMeasureGeometry.Transform; - - var finalSize = new Size(100, 50); - var finalRect = new Rect(finalSize); - shape.Arrange(finalRect); - - Geometry postArrangeGeometry = shape.RenderedGeometry; - Transform postArrangeTransform = postArrangeGeometry.Transform; - - Assert.Equal(postMeasureGeometry, postArrangeGeometry); - Assert.Equal(postMeasureTransform, postArrangeTransform); - Assert.Equal(finalSize, shape.Bounds.Size); - } - } -} From 41050b67422be08b8b15700f3e99fd5879acb58a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 13 Oct 2020 18:26:34 +0200 Subject: [PATCH 7/9] Added some tests for Rectangle and Ellipse. Because these classes override the base `Shape` layout. --- .../Shapes/EllipseTests.cs | 57 +++++++++++++++++++ .../Shapes/RectangleTests.cs | 56 ++++++++++++++++-- 2 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 tests/Avalonia.Controls.UnitTests/Shapes/EllipseTests.cs diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/EllipseTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/EllipseTests.cs new file mode 100644 index 0000000000..626945894f --- /dev/null +++ b/tests/Avalonia.Controls.UnitTests/Shapes/EllipseTests.cs @@ -0,0 +1,57 @@ +using Avalonia.Controls.Shapes; +using Avalonia.Media; +using Avalonia.UnitTests; +using Xunit; + +namespace Avalonia.Controls.UnitTests.Shapes +{ + public class EllipseTests + { + [Fact] + public void Measure_Does_Not_Set_RenderedGeometry_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Ellipse(); + + target.Measure(new Size(100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(default, geometry.Rect); + } + + [Fact] + public void Arrange_Sets_RenderedGeometry_Properties() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Ellipse(); + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 100, 100), geometry.Rect); + } + + [Fact] + public void Rearranging_Updates_RenderedGeometry_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Ellipse(); + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 100, 100), geometry.Rect); + + target.Measure(new Size(200, 200)); + target.Arrange(new Rect(0, 0, 200, 200)); + + geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 200, 200), geometry.Rect); + } + } +} diff --git a/tests/Avalonia.Controls.UnitTests/Shapes/RectangleTests.cs b/tests/Avalonia.Controls.UnitTests/Shapes/RectangleTests.cs index 0ec73edec0..8d8ce10d4c 100644 --- a/tests/Avalonia.Controls.UnitTests/Shapes/RectangleTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Shapes/RectangleTests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Avalonia.Controls.Shapes; +using Avalonia.Controls.Shapes; using Avalonia.Media; using Avalonia.UnitTests; using Moq; @@ -11,6 +8,53 @@ namespace Avalonia.Controls.UnitTests.Shapes { public class RectangleTests { + [Fact] + public void Measure_Does_Not_Set_RenderedGeometry_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Rectangle(); + + target.Measure(new Size(100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(Rect.Empty, geometry.Rect); + } + + [Fact] + public void Arrange_Sets_RenderedGeometry_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Rectangle(); + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 100, 100), geometry.Rect); + } + + [Fact] + public void Rearranging_Updates_RenderedGeometry_Rect() + { + using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + var target = new Rectangle(); + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + + var geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 100, 100), geometry.Rect); + + target.Measure(new Size(200, 200)); + target.Arrange(new Rect(0, 0, 200, 200)); + + geometry = Assert.IsType(target.RenderedGeometry); + Assert.Equal(new Rect(0, 0, 200, 200), geometry.Rect); + } + [Fact] public void Changing_Fill_Brush_Color_Should_Invalidate_Visual() { @@ -21,7 +65,7 @@ namespace Avalonia.Controls.UnitTests.Shapes var root = new TestRoot(target); var renderer = Mock.Get(root.Renderer); - renderer.ResetCalls(); + renderer.Invocations.Clear(); ((SolidColorBrush)target.Fill).Color = Colors.Green; @@ -38,7 +82,7 @@ namespace Avalonia.Controls.UnitTests.Shapes var root = new TestRoot(target); var renderer = Mock.Get(root.Renderer); - renderer.ResetCalls(); + renderer.Invocations.Clear(); ((SolidColorBrush)target.Stroke).Color = Colors.Green; From d96c157231c24cc3a167cfa6be10cc13a92b80be Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 15 Oct 2020 11:40:53 +0200 Subject: [PATCH 8/9] Name tuple values. --- src/Avalonia.Controls/Shapes/Shape.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index 28206a398a..cd16ac402d 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -252,7 +252,7 @@ namespace Avalonia.Controls.Shapes return default; } - return CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch).Item1; + return CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch).size; } protected override Size ArrangeOverride(Size finalSize) @@ -275,7 +275,7 @@ namespace Avalonia.Controls.Shapes return Size.Empty; } - internal static (Size, Matrix) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch) + internal static (Size size, Matrix transform) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch) { Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom); Matrix translate = Matrix.Identity; From cf6032d8e4d726c97e78f678f6c7630dc52d6235 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 15 Oct 2020 11:41:36 +0200 Subject: [PATCH 9/9] Discard unused value. --- src/Avalonia.Controls/Shapes/Shape.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index cd16ac402d..0b7595ec9a 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -261,7 +261,7 @@ namespace Avalonia.Controls.Shapes { // This should probably use GetRenderBounds(strokeThickness) but then the calculations // will multiply the stroke thickness as well, which isn't correct. - var (size, transform) = CalculateSizeAndTransform(finalSize, DefiningGeometry.Bounds, Stretch); + var (_, transform) = CalculateSizeAndTransform(finalSize, DefiningGeometry.Bounds, Stretch); if (_transform != transform) {