| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- #nullable enable
- using UnitTests;
- namespace ViewBaseTests.Drawing;
- /// <summary>
- /// Tests for the static View.Draw(IEnumerable<View>, bool) method
- /// </summary>
- [Trait ("Category", "Output")]
- public class StaticDrawTests : FakeDriverBase
- {
- [Fact]
- public void StaticDraw_ClearsSubViewNeedsDraw_AfterMarginDrawMargins ()
- {
- // This test validates the fix where the static Draw method calls ClearNeedsDraw()
- // on all peer views after drawing them AND after calling Margin.DrawMargins().
- //
- // THE BUG (before the fix):
- // Margin.DrawMargins() can cause SubViewNeedsDraw to be set on views in the hierarchy.
- // This would leave SubViewNeedsDraw = true even after drawing completed.
- //
- // THE FIX (current code):
- // The static Draw() method explicitly calls ClearNeedsDraw() on all peer views
- // at the very end, AFTER Margin.DrawMargins(), clearing any SubViewNeedsDraw flags
- // that were set during margin drawing.
- IDriver driver = CreateFakeDriver ();
- driver.Clip = new (driver.Screen);
- // Create a view hierarchy where a subview's subview has a margin
- // This reproduces the scenario where Margin.DrawMargins sets SubViewNeedsDraw
- View superview = new ()
- {
- X = 0,
- Y = 0,
- Width = 60,
- Height = 60,
- Driver = driver,
- Id = "SuperView"
- };
- View subview1 = new () { X = 0, Y = 0, Width = 40, Height = 40, Id = "SubView1" };
- View subview2 = new () { X = 0, Y = 20, Width = 20, Height = 20, Id = "SubView2" };
- // Add a subview to subview1 that has a margin with shadow
- // This is key to reproducing the bug
- View subSubView = new ()
- {
- X = 5,
- Y = 5,
- Width = 20,
- Height = 20,
- Id = "SubSubView"
- };
- subSubView.Margin!.Thickness = new (1);
- subSubView.Margin.ShadowStyle = ShadowStyle.Transparent;
- subview1.Add (subSubView);
- superview.Add (subview1, subview2);
- superview.BeginInit ();
- superview.EndInit ();
- superview.LayoutSubViews ();
- // All views initially need drawing
- Assert.True (superview.NeedsDraw);
- Assert.True (superview.SubViewNeedsDraw);
- Assert.True (subview1.NeedsDraw);
- Assert.True (subview1.SubViewNeedsDraw);
- Assert.True (subview2.NeedsDraw);
- Assert.True (subSubView.NeedsDraw);
- Assert.True (subSubView.Margin.NeedsDraw);
- // Call the static Draw method on the subviews
- // This will:
- // 1. Call view.Draw() on each subview
- // 2. Call Margin.DrawMargins() which may set SubViewNeedsDraw in the hierarchy
- // 3. Call ClearNeedsDraw() on each subview to clean up
- View.Draw (superview.InternalSubViews, force: false);
- // After the static Draw completes:
- // All subviews should have NeedsDraw = false
- Assert.False (subview1.NeedsDraw, "SubView1 should not need drawing after Draw()");
- Assert.False (subview2.NeedsDraw, "SubView2 should not need drawing after Draw()");
- Assert.False (subSubView.NeedsDraw, "SubSubView should not need drawing after Draw()");
- Assert.False (subSubView.Margin.NeedsDraw, "SubSubView's Margin should not need drawing after Draw()");
- // SuperView's SubViewNeedsDraw should be false because the static Draw() method
- // calls ClearNeedsDraw() on all the subviews at the end, AFTER Margin.DrawMargins()
- //
- // BEFORE THE FIX: This would be TRUE because Margin.DrawMargins() would
- // set SubViewNeedsDraw somewhere in the hierarchy and it
- // wouldn't be cleared
- // AFTER THE FIX: This is FALSE because the static Draw() calls ClearNeedsDraw()
- // at the very end, cleaning up any SubViewNeedsDraw flags set
- // by Margin.DrawMargins()
- Assert.False (superview.SubViewNeedsDraw,
- "superview's SubViewNeedsDraw should be false after static Draw(). All subviews were drawn in the call to View.Draw");
- Assert.False (subview1.SubViewNeedsDraw,
- "SubView1's SubViewNeedsDraw should be false after its subviews are drawn and cleared");
- }
- [Fact]
- public void StaticDraw_WithForceTrue_SetsNeedsDrawOnAllViews ()
- {
- // Verify that when force=true, all views get SetNeedsDraw() called before drawing
- IDriver driver = CreateFakeDriver ();
- driver.Clip = new (driver.Screen);
- View view1 = new () { X = 0, Y = 0, Width = 10, Height = 10, Driver = driver, Id = "View1" };
- View view2 = new () { X = 10, Y = 0, Width = 10, Height = 10, Driver = driver, Id = "View2" };
- view1.BeginInit ();
- view1.EndInit ();
- view2.BeginInit ();
- view2.EndInit ();
- // Manually clear their NeedsDraw flags
- view1.Draw ();
- view2.Draw ();
- Assert.False (view1.NeedsDraw);
- Assert.False (view2.NeedsDraw);
- // Now call static Draw with force=true
- View.Draw ([view1, view2], force: true);
- // After drawing with force=true, they should be cleared again
- Assert.False (view1.NeedsDraw);
- Assert.False (view2.NeedsDraw);
- }
- [Fact]
- public void StaticDraw_HandlesEmptyCollection ()
- {
- // Verify that calling Draw with an empty collection doesn't crash
- View.Draw ([], force: false);
- View.Draw ([], force: true);
- }
- [Fact]
- public void StaticDraw_ClearsNestedSubViewNeedsDraw ()
- {
- // This test verifies that the static Draw method properly clears SubViewNeedsDraw
- // flags throughout a nested view hierarchy after Margin.DrawMargins
- IDriver driver = CreateFakeDriver ();
- driver.Clip = new (driver.Screen);
- View topView = new ()
- {
- X = 0,
- Y = 0,
- Width = 60,
- Height = 60,
- Driver = driver,
- Id = "TopView"
- };
- View middleView1 = new () { X = 0, Y = 0, Width = 30, Height = 30, Id = "MiddleView1" };
- View middleView2 = new () { X = 30, Y = 0, Width = 30, Height = 30, Id = "MiddleView2" };
- View bottomView = new ()
- {
- X = 5,
- Y = 5,
- Width = 15,
- Height = 15,
- Id = "BottomView"
- };
- // Give the bottom view a margin to trigger the Margin.DrawMargins behavior
- bottomView.Margin!.Thickness = new (1);
- bottomView.Margin.ShadowStyle = ShadowStyle.Transparent;
- middleView1.Add (bottomView);
- topView.Add (middleView1, middleView2);
- topView.BeginInit ();
- topView.EndInit ();
- topView.LayoutSubViews ();
- Assert.True (topView.SubViewNeedsDraw);
- Assert.True (middleView1.SubViewNeedsDraw);
- Assert.True (bottomView.NeedsDraw);
- // Draw the middle views using static Draw
- View.Draw (topView.InternalSubViews, force: false);
- // All SubViewNeedsDraw flags should be cleared after the static Draw
- Assert.False (topView.SubViewNeedsDraw,
- "TopView's SubViewNeedsDraw should be false after static Draw(). All subviews were drawn in the call to View.Draw");
- Assert.False (middleView1.SubViewNeedsDraw,
- "MiddleView1's SubViewNeedsDraw should be false after its subviews are drawn");
- Assert.False (middleView2.SubViewNeedsDraw,
- "MiddleView2's SubViewNeedsDraw should be false");
- Assert.False (bottomView.NeedsDraw,
- "BottomView should not need drawing after Draw()");
- Assert.False (bottomView.Margin.NeedsDraw,
- "BottomView's Margin should not need drawing after Draw()");
- }
- }
|