| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- #nullable enable
- using UnitTests;
- using Xunit.Abstractions;
- namespace UnitTests_Parallelizable.ViewTests;
- public class ViewDrawingClippingTests () : FakeDriverBase
- {
- #region GetClip / SetClip Tests
- [Fact]
- public void GetClip_ReturnsDriverClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var region = new Region (new Rectangle (10, 10, 20, 20));
- driver.Clip = region;
- View view = new () { Driver = driver };
- Region? result = view.GetClip ();
- Assert.NotNull (result);
- Assert.Equal (region, result);
- }
- [Fact]
- public void SetClip_NullRegion_DoesNothing ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var original = new Region (new Rectangle (5, 5, 10, 10));
- driver.Clip = original;
- View view = new () { Driver = driver };
- view.SetClip (null);
- Assert.Equal (original, driver.Clip);
- }
- [Fact]
- public void SetClip_ValidRegion_SetsDriverClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var region = new Region (new Rectangle (10, 10, 30, 30));
- View view = new () { Driver = driver };
- view.SetClip (region);
- Assert.Equal (region, driver.Clip);
- }
- #endregion
- #region SetClipToScreen Tests
- [Fact]
- public void SetClipToScreen_ReturnsPreviousClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var original = new Region (new Rectangle (5, 5, 10, 10));
- driver.Clip = original;
- View view = new () { Driver = driver };
- Region? previous = view.SetClipToScreen ();
- Assert.Equal (original, previous);
- Assert.NotEqual (original, driver.Clip);
- }
- [Fact]
- public void SetClipToScreen_SetsClipToScreen ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- View view = new () { Driver = driver };
- view.SetClipToScreen ();
- Assert.NotNull (driver.Clip);
- Assert.Equal (driver.Screen, driver.Clip.GetBounds ());
- }
- #endregion
- #region ExcludeFromClip Tests
- [Fact]
- public void ExcludeFromClip_Rectangle_NullDriver_DoesNotThrow ()
- {
- View view = new () { Driver = null };
- var exception = Record.Exception (() => view.ExcludeFromClip (new Rectangle (5, 5, 10, 10)));
- Assert.Null (exception);
- }
- [Fact]
- public void ExcludeFromClip_Rectangle_ExcludesArea ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (new Rectangle (0, 0, 80, 25));
- View view = new () { Driver = driver };
- var toExclude = new Rectangle (10, 10, 20, 20);
- view.ExcludeFromClip (toExclude);
- // Verify the region was excluded
- Assert.NotNull (driver.Clip);
- Assert.False (driver.Clip.Contains (15, 15));
- }
- [Fact]
- public void ExcludeFromClip_Region_NullDriver_DoesNotThrow ()
- {
- View view = new () { Driver = null };
- var exception = Record.Exception (() => view.ExcludeFromClip (new Region (new Rectangle (5, 5, 10, 10))));
- Assert.Null (exception);
- }
- [Fact]
- public void ExcludeFromClip_Region_ExcludesArea ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (new Rectangle (0, 0, 80, 25));
- View view = new () { Driver = driver };
- var toExclude = new Region (new Rectangle (10, 10, 20, 20));
- view.ExcludeFromClip (toExclude);
- // Verify the region was excluded
- Assert.NotNull (driver.Clip);
- Assert.False (driver.Clip.Contains (15, 15));
- }
- #endregion
- #region AddFrameToClip Tests
- [Fact]
- public void AddFrameToClip_NullDriver_ReturnsNull ()
- {
- var view = new View { X = 0, Y = 0, Width = 10, Height = 10 };
- view.BeginInit ();
- view.EndInit ();
- Region? result = view.AddFrameToClip ();
- Assert.Null (result);
- }
- [Fact]
- public void AddFrameToClip_IntersectsWithFrame ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddFrameToClip ();
- Assert.NotNull (previous);
- Assert.NotNull (driver.Clip);
- // The clip should now be the intersection of the screen and the view's frame
- Rectangle expectedBounds = new Rectangle (1, 1, 20, 20);
- Assert.Equal (expectedBounds, driver.Clip.GetBounds ());
- }
- #endregion
- #region AddViewportToClip Tests
- [Fact]
- public void AddViewportToClip_NullDriver_ReturnsNull ()
- {
- var view = new View { X = 0, Y = 0, Width = 10, Height = 10 };
- view.BeginInit ();
- view.EndInit ();
- Region? result = view.AddViewportToClip ();
- Assert.Null (result);
- }
- [Fact]
- public void AddViewportToClip_IntersectsWithViewport ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddViewportToClip ();
- Assert.NotNull (previous);
- Assert.NotNull (driver.Clip);
- // The clip should be the viewport area
- Rectangle viewportScreen = view.ViewportToScreen (new Rectangle (Point.Empty, view.Viewport.Size));
- Assert.Equal (viewportScreen, driver.Clip.GetBounds ());
- }
- [Fact]
- public void AddViewportToClip_WithClipContentOnly_LimitsToVisibleContent ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.SetContentSize (new Size (100, 100));
- view.ViewportSettings = ViewportSettingsFlags.ClipContentOnly;
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddViewportToClip ();
- Assert.NotNull (previous);
- Assert.NotNull (driver.Clip);
- // The clip should be limited to visible content
- Rectangle visibleContent = view.ViewportToScreen (new Rectangle (new (-view.Viewport.X, -view.Viewport.Y), view.GetContentSize ()));
- Rectangle viewport = view.ViewportToScreen (new Rectangle (Point.Empty, view.Viewport.Size));
- Rectangle expected = Rectangle.Intersect (viewport, visibleContent);
- Assert.Equal (expected, driver.Clip.GetBounds ());
- }
- #endregion
- #region Clip Interaction Tests
- [Fact]
- public void ClipRegions_StackCorrectly_WithNestedViews ()
- {
- IDriver driver = CreateFakeDriver (100, 100);
- driver.Clip = new Region (driver.Screen);
- var superView = new View
- {
- X = 1,
- Y = 1,
- Width = 50,
- Height = 50,
- Driver = driver
- };
- superView.BeginInit ();
- superView.EndInit ();
- var view = new View
- {
- X = 5,
- Y = 5,
- Width = 30,
- Height = 30,
- };
- superView.Add (view);
- superView.LayoutSubViews ();
- // Set clip to superView's frame
- Region? superViewClip = superView.AddFrameToClip ();
- Rectangle superViewBounds = driver.Clip.GetBounds ();
- // Now set clip to view's frame
- Region? viewClip = view.AddFrameToClip ();
- Rectangle viewBounds = driver.Clip.GetBounds ();
- // Child clip should be within superView clip
- Assert.True (superViewBounds.Contains (viewBounds.Location));
- // Restore superView clip
- view.SetClip (superViewClip);
- // Assert.Equal (superViewBounds, driver.Clip.GetBounds ());
- }
- [Fact]
- public void ClipRegions_RespectPreviousClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var initialClip = new Region (new Rectangle (20, 20, 40, 40));
- driver.Clip = initialClip;
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 60,
- Height = 60,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddFrameToClip ();
- // The new clip should be the intersection of the initial clip and the view's frame
- Rectangle expected = Rectangle.Intersect (
- initialClip.GetBounds (),
- view.FrameToScreen ()
- );
- Assert.Equal (expected, driver.Clip.GetBounds ());
- // Restore should give us back the original
- view.SetClip (previous);
- Assert.Equal (initialClip.GetBounds (), driver.Clip.GetBounds ());
- }
- #endregion
- #region Edge Cases
- [Fact]
- public void AddFrameToClip_EmptyFrame_WorksCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 0,
- Height = 0,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddFrameToClip ();
- Assert.NotNull (previous);
- Assert.NotNull (driver.Clip);
- }
- [Fact]
- public void AddViewportToClip_EmptyViewport_WorksCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 1, // Minimal size to have adornments
- Height = 1,
- Driver = driver
- };
- view.Border!.Thickness = new Thickness (1);
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- // With border thickness of 1, the viewport should be empty
- Assert.True (view.Viewport.Size.Width == 0 || view.Viewport.Size.Height == 0);
- Region? previous = view.AddViewportToClip ();
- Assert.NotNull (previous);
- }
- [Fact]
- public void ClipRegions_OutOfBounds_HandledCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 100, // Outside screen bounds
- Y = 100,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region? previous = view.AddFrameToClip ();
- Assert.NotNull (previous);
- // The clip should be empty since the view is outside the screen
- Assert.True (driver.Clip.IsEmpty () || !driver.Clip.Contains (100, 100));
- }
- #endregion
- #region Drawing Tests
- [Fact]
- public void Clip_Set_BeforeDraw_ClipsDrawing ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var clip = new Region (new Rectangle (10, 10, 10, 10));
- driver.Clip = clip;
- var view = new View
- {
- X = 0,
- Y = 0,
- Width = 50,
- Height = 50,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- view.Draw ();
- // Verify clip was used
- Assert.NotNull (driver.Clip);
- }
- [Fact]
- public void Draw_UpdatesDriverClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 1,
- Y = 1,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- view.Draw ();
- // Clip should be updated to exclude the drawn view
- Assert.NotNull (driver.Clip);
- // Assert.False (driver.Clip.Contains (15, 15)); // Point inside the view should be excluded
- }
- [Fact]
- public void Draw_WithSubViews_ClipsCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var superView = new View
- {
- X = 1,
- Y = 1,
- Width = 50,
- Height = 50,
- Driver = driver
- };
- var view = new View { X = 5, Y = 5, Width = 20, Height = 20 };
- superView.Add (view);
- superView.BeginInit ();
- superView.EndInit ();
- superView.LayoutSubViews ();
- superView.Draw ();
- // Both superView and view should be excluded from clip
- Assert.NotNull (driver.Clip);
- // Assert.False (driver.Clip.Contains (15, 15)); // Point in superView should be excluded
- }
- [Fact]
- public void Draw_NonVisibleView_DoesNotUpdateClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var originalClip = new Region (driver.Screen);
- driver.Clip = originalClip.Clone ();
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Visible = false,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.Draw ();
- // Clip should not be modified for invisible views
- Assert.True (driver.Clip.Equals (originalClip));
- }
- [Fact]
- public void ExcludeFromClip_ExcludesRegion ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- var excludeRect = new Rectangle (15, 15, 10, 10);
- view.ExcludeFromClip (excludeRect);
- Assert.NotNull (driver.Clip);
- Assert.False (driver.Clip.Contains (20, 20)); // Point inside excluded rect should not be in clip
- }
- [Fact]
- public void ExcludeFromClip_WithNullClip_DoesNotThrow ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = null!;
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- var exception = Record.Exception (() => view.ExcludeFromClip (new Rectangle (15, 15, 10, 10)));
- Assert.Null (exception);
- }
- #endregion
- #region Misc Tests
- [Fact]
- public void SetClip_SetsDriverClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- var newClip = new Region (new Rectangle (5, 5, 30, 30));
- view.SetClip (newClip);
- Assert.Equal (newClip, driver.Clip);
- }
- [Fact (Skip = "See BUGBUG in SetClip")]
- public void SetClip_WithNullClip_ClearsClip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (new Rectangle (10, 10, 20, 20));
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.SetClip (null);
- Assert.Null (driver.Clip);
- }
- [Fact]
- public void Draw_Excludes_View_From_Clip ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- var originalClip = new Region (driver.Screen);
- driver.Clip = originalClip.Clone ();
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 20,
- Height = 20,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- Region clipWithViewExcluded = originalClip.Clone ();
- clipWithViewExcluded.Exclude (view.Frame);
- view.Draw ();
- Assert.Equal (clipWithViewExcluded, driver.Clip);
- Assert.NotNull (driver.Clip);
- }
- [Fact]
- public void Draw_EmptyViewport_DoesNotCrash ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 10,
- Y = 10,
- Width = 1,
- Height = 1,
- Driver = driver
- };
- view.Border!.Thickness = new Thickness (1);
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- // With border of 1, viewport should be empty (0x0 or negative)
- var exception = Record.Exception (() => view.Draw ());
- Assert.Null (exception);
- }
- [Fact]
- public void Draw_VeryLargeView_HandlesClippingCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 0,
- Y = 0,
- Width = 1000,
- Height = 1000,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- var exception = Record.Exception (() => view.Draw ());
- Assert.Null (exception);
- }
- [Fact]
- public void Draw_NegativeCoordinates_HandlesClippingCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = -10,
- Y = -10,
- Width = 50,
- Height = 50,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- var exception = Record.Exception (() => view.Draw ());
- Assert.Null (exception);
- }
- [Fact]
- public void Draw_OutOfScreenBounds_HandlesClippingCorrectly ()
- {
- IDriver driver = CreateFakeDriver (80, 25);
- driver.Clip = new Region (driver.Screen);
- var view = new View
- {
- X = 100,
- Y = 100,
- Width = 50,
- Height = 50,
- Driver = driver
- };
- view.BeginInit ();
- view.EndInit ();
- view.LayoutSubViews ();
- var exception = Record.Exception (() => view.Draw ());
- Assert.Null (exception);
- }
- #endregion
- }
|