#nullable enable namespace ViewBaseTests.Layout; [Trait ("Category", "Input")] public class GetViewsUnderLocationForRootTests { [Fact] public void ReturnsRoot_WhenPointInsideRoot_NoSubviews () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; List result = View.GetViewsUnderLocation (top, new (5, 5), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); } [Fact] public void ReturnsEmpty_WhenPointOutsideRoot () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; List result = View.GetViewsUnderLocation (top, new (20, 20), ViewportSettingsFlags.TransparentMouse); Assert.Empty (result); } [Fact] public void ReturnsSubview_WhenPointInsideSubview () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; View sub = new () { X = 2, Y = 2, Width = 5, Height = 5 }; top.Add (sub); List result = View.GetViewsUnderLocation (top, new (3, 3), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (sub, result); Assert.Equal (sub, result.Last ()); } [Fact] public void ReturnsTop_WhenPointInsideSubview_With_TransparentMouse () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; View sub = new () { X = 2, Y = 2, Width = 5, Height = 5, ViewportSettings = ViewportSettingsFlags.TransparentMouse }; top.Add (sub); List result = View.GetViewsUnderLocation (top, new (3, 3), ViewportSettingsFlags.TransparentMouse); Assert.Single (result); Assert.Contains (top, result); result = View.GetViewsUnderLocation (top, new (3, 3), ViewportSettingsFlags.None); Assert.Equal (2, result.Count); Assert.Contains (top, result); Assert.Contains (sub, result); } [Fact] public void ReturnsAdornment_WhenPointInMargin () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; top.Margin!.Thickness = new (1); top.Margin!.ViewportSettings = ViewportSettingsFlags.None; List result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (top.Margin, result); } [Fact] public void Returns_WhenPointIn_TransparentToMouseMargin_None () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; top.Margin!.Thickness = new (1); top.Margin!.ViewportSettings = ViewportSettingsFlags.TransparentMouse; List result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); Assert.DoesNotContain (top, result); Assert.DoesNotContain (top.Margin, result); } [Fact] public void Returns_WhenPointIn_NotTransparentToMouseMargin_Top_And_Margin () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; top.Margin!.Thickness = new (1); top.Margin!.ViewportSettings = ViewportSettingsFlags.None; List result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (top.Margin, result); } [Fact] public void ReturnsAdornment_WhenPointInBorder () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; top.Border!.Thickness = new (1); List result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (top.Border, result); } [Fact] public void ReturnsAdornment_WhenPointInPadding () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; top.Border!.Thickness = new (1); top.Padding!.Thickness = new (1); top.Layout (); List result = View.GetViewsUnderLocation (top, new (1, 1), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (top.Padding, result); } [Fact] public void HonorsIgnoreTransparentMouseParam () { Runnable top = new () { Frame = new (0, 0, 10, 10), ViewportSettings = ViewportSettingsFlags.TransparentMouse }; List result = View.GetViewsUnderLocation (top, new (5, 5), ViewportSettingsFlags.TransparentMouse); Assert.Empty (result); result = View.GetViewsUnderLocation (top, new (5, 5), ViewportSettingsFlags.None); Assert.NotEmpty (result); } [Fact] public void ReturnsDeepestSubview_WhenNested () { Runnable top = new () { Frame = new (0, 0, 10, 10) }; View sub1 = new () { X = 1, Y = 1, Width = 8, Height = 8 }; View sub2 = new () { X = 1, Y = 1, Width = 6, Height = 6 }; sub1.Add (sub2); top.Add (sub1); List result = View.GetViewsUnderLocation (top, new (3, 3), ViewportSettingsFlags.TransparentMouse); Assert.Contains (sub2, result); Assert.Equal (sub2, result.Last ()); } [Fact] public void Returns_Subview_WhenPointIn_TransparentToMouseMargin_Top () { Runnable top = new () { Frame = new (0, 0, 20, 20) }; View subView = new () { Frame = new (0, 0, 5, 5) }; subView.Margin!.Thickness = new (1); subView.Margin!.ViewportSettings = ViewportSettingsFlags.None; top.Add (subView); Assert.True (subView.Contains (new Point (4, 4))); List result = View.GetViewsUnderLocation (top, new (4, 4), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.Contains (subView.Margin, result); Assert.Contains (subView, result); subView.Margin!.ViewportSettings = ViewportSettingsFlags.TransparentMouse; result = View.GetViewsUnderLocation (top, new (4, 4), ViewportSettingsFlags.TransparentMouse); Assert.Contains (top, result); Assert.DoesNotContain (subView.Margin, result); Assert.DoesNotContain (subView, result); } [Theory] [InlineData ("Margin")] [InlineData ("Border")] [InlineData ("Padding")] public void Returns_Subview_Of_Adornment (string adornmentType) { // Arrange: top -> subView -> subView.[Adornment] -> adornmentSubView Runnable top = new () { Frame = new (0, 0, 10, 10) }; View subView = new () { X = 0, Y = 0, Width = 8, Height = 8 }; top.Add (subView); View? adornment = null; switch (adornmentType) { case "Margin": subView.Margin!.Thickness = new (2); adornment = subView.Margin; break; case "Border": subView.Border!.Thickness = new (2); adornment = subView.Border; break; case "Padding": subView.Padding!.Thickness = new (2); adornment = subView.Padding; break; } subView.Layout (); // Add a child to the adornment View adornmentSubView = new () { X = 0, Y = 0, Width = 2, Height = 2 }; adornment!.Add (adornmentSubView); // Set adornment ViewportSettings to None so it doesn't interfere with the test adornment.ViewportSettings = ViewportSettingsFlags.None; // Act: Point inside adornmentSubView (which is inside the adornment) var result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); // Assert: Should contain top, subView, adornment, and adornmentSubView Assert.Contains (top, result); Assert.Contains (subView, result); Assert.Contains (adornment, result); Assert.Contains (adornmentSubView, result); Assert.Equal (top, result [0]); Assert.Equal (adornmentSubView, result [^1]); } [Theory] [InlineData ("Margin")] [InlineData ("Border")] [InlineData ("Padding")] public void Returns_OnlyParentsSuperView_Of_Adornment_If_TransparentMouse (string adornmentType) { // Arrange: top -> subView -> subView.[Adornment] -> adornmentSubView Runnable top = new () { Id = "top", Frame = new (0, 0, 10, 10) }; View subView = new () { Id = "subView", X = 0, Y = 0, Width = 8, Height = 8 }; top.Add (subView); View? adornment = null; switch (adornmentType) { case "Margin": subView.Margin!.Thickness = new (2); adornment = subView.Margin; break; case "Border": subView.Border!.Thickness = new (2); adornment = subView.Border; break; case "Padding": subView.Padding!.Thickness = new (2); adornment = subView.Padding; break; } subView.Layout (); // Add a child to the adornment View adornmentSubView = new () { Id = "adornmentSubView", X = 0, Y = 0, Width = 2, Height = 2 }; adornment!.Add (adornmentSubView); adornment.ViewportSettings = ViewportSettingsFlags.TransparentMouse; // Act: Point inside adornmentSubView (which is inside the adornment) var result = View.GetViewsUnderLocation (top, new (0, 0), ViewportSettingsFlags.TransparentMouse); // Assert: Should contain top, subView, adornment, and adornmentSubView Assert.Contains (top, result); Assert.DoesNotContain (adornment, result); Assert.Contains (adornmentSubView, result); Assert.DoesNotContain (subView, result); Assert.Equal (top, result [0]); Assert.Equal (adornmentSubView, result [^1]); } }