using Xunit.Abstractions; namespace Terminal.Gui.ViewsTests; public class TileViewTests { private readonly ITestOutputHelper _output; public TileViewTests (ITestOutputHelper output) { _output = output; } [Fact] [AutoInitShutdown] public void Test_SplitTop_WholeBottom () { var tileView = new TileView (2) { Width = 20, Height = 10, Orientation = Orientation.Horizontal, LineStyle = LineStyle.Single }; Assert.True (tileView.TrySplitTile (0, 2, out TileView top)); top.Tiles.ElementAt (0).ContentView.Add (new Label { Text = "bleh" }); top.Tiles.ElementAt (1).ContentView.Add (new Label { Text = "blah" }); top.BeginInit (); top.EndInit (); top.LayoutSubviews (); tileView.Tiles.ElementAt (1).ContentView.Add (new Label { Text = "Hello" }); tileView.ColorScheme = new ColorScheme (); top.ColorScheme = new ColorScheme (); tileView.BeginInit (); tileView.EndInit (); tileView.LayoutSubviews (); tileView.Draw (); var looksLike = @" ┌─────────┬────────┐ │bleh │blah │ │ │ │ │ │ │ │ │ │ ├─────────┴────────┤ │Hello │ │ │ │ │ └──────────────────┘"; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter1 () { TileView tv = Get5x1TilesView (); tv.Tiles.ElementAt (0).MinSize = int.MaxValue; tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 0; x <= 5; x++) { // All these values would result in tile 0 getting smaller // so are not allowed (tile[0] has a min size of Int.Max) Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 6; x < 10; x++) { // All these values would result in tile 0 getting bigger // so are allowed Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 10; x < 100; x++) { // These values would result in the first splitter moving past // the second splitter so are not allowed Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────────┬┬────┬────┬───┐ │11111111││3333│4444│555│ │ ││ │ │ │ └────────┴┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter1_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Tiles.ElementAt (0).MinSize = int.MaxValue; tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 0; x <= 5; x++) { // All these values would result in tile 0 getting smaller // so are not allowed (tile[0] has a min size of Int.Max) Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 6; x < 10; x++) { // All these values would result in tile 0 getting bigger // so are allowed Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 10; x < 100; x++) { // These values would result in the first splitter moving past // the second splitter so are not allowed Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 111111111││3333│4444│5555 ││ │ │ ││ │ │ ││ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter2 () { TileView tv = Get5x1TilesView (); tv.Tiles.ElementAt (1).MinSize = 2; tv.Tiles.ElementAt (2).MinSize = 3; tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x > 7; x--) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 7; x > 0; x--) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬──┬──────┬────┬───┐ │1111│22│333333│4444│555│ │ │ │ │ │ │ └────┴──┴──────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x < 12; x++) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 12; x < 25; x++) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬─────┬───┬────┬───┐ │1111│22222│333│4444│555│ │ │ │ │ │ │ └────┴─────┴───┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter2_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Tiles.ElementAt (1).MinSize = 2; tv.Tiles.ElementAt (2).MinSize = 3; tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x > 7; x--) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 7; x > 0; x--) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│22│333333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x < 12; x++) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 12; x < 25; x++) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│22222│333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter4 () { TileView tv = Get5x1TilesView (); tv.Tiles.ElementAt (3).MinSize = 2; tv.Tiles.ElementAt (4).MinSize = 1; tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x > 17; x--) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 17; x > 0; x--) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬────┬────┬──┬─────┐ │1111│2222│3333│44│55555│ │ │ │ │ │ │ └────┴────┴────┴──┴─────┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x < 23; x++) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 23; x < 100; x++) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬────┬────┬──────┬─┐ │1111│2222│3333│444444│5│ │ │ │ │ │ │ └────┴────┴────┴──────┴─┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter4_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Tiles.ElementAt (3).MinSize = 2; tv.Tiles.ElementAt (4).MinSize = 1; tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x > 17; x--) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 17; x > 0; x--) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│2222│3333│44│555555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x < 24; x++) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 24; x < 100; x++) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│2222│3333│4444444│5 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter1_CannotCrossBorder () { TileView tv = Get5x1TilesView (); tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 5; x > 0; x--) { Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } Assert.False (tv.SetSplitterPos (0, 0)); tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌┬────────┬────┬────┬───┐ ││22222222│3333│4444│555│ ││ │ │ │ │ └┴────────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 6; x < 10; x++) { Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 10; x < 100; x++) { // These values would result in the first splitter moving past // the second splitter so are not allowed Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────────┬┬────┬────┬───┐ │11111111││3333│4444│555│ │ ││ │ │ │ └────────┴┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter1_CannotCrossBorder_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 5; x >= 0; x--) { Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" │222222222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 6; x < 10; x++) { Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } for (var x = 10; x < 100; x++) { // These values would result in the first splitter moving past // the second splitter so are not allowed Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 111111111││3333│4444│5555 ││ │ │ ││ │ │ ││ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter2_CannotMoveOverNeighbours () { TileView tv = Get5x1TilesView (); tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x > 5; x--) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 5; x > 0; x--) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬┬────────┬────┬───┐ │1111││33333333│4444│555│ │ ││ │ │ │ └────┴┴────────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x < 15; x++) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 15; x < 25; x++) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬────────┬┬────┬───┐ │1111│22222222││4444│555│ │ │ ││ │ │ └────┴────────┴┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter2_CannotMoveOverNeighbours_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x > 5; x--) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 5; x > 0; x--) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111││33333333│4444│5555 ││ │ │ ││ │ │ ││ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 10; x < 15; x++) { Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } for (var x = 15; x < 25; x++) { Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│22222222││4444│5555 │ ││ │ │ ││ │ │ ││ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter4_CannotMoveOverNeighbours () { TileView tv = Get5x1TilesView (); tv.Draw (); var looksLike = @" ┌────┬────┬────┬────┬───┐ │1111│2222│3333│4444│555│ │ │ │ │ │ │ └────┴────┴────┴────┴───┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x > 15; x--) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 15; x > 0; x--) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬────┬────┬┬───────┐ │1111│2222│3333││5555555│ │ │ │ ││ │ └────┴────┴────┴┴───────┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x < 24; x++) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 24; x < 100; x++) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" ┌────┬────┬────┬───────┬┐ │1111│2222│3333│4444444││ │ │ │ │ ││ └────┴────┴────┴───────┴┘ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] [AutoInitShutdown] public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter4_CannotMoveOverNeighbours_NoBorder () { TileView tv = Get5x1TilesView (false); tv.Draw (); var looksLike = @" 11111│2222│3333│4444│5555 │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x > 15; x--) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 15; x > 0; x--) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│2222│3333││55555555 │ │ ││ │ │ ││ │ │ ││ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); for (var x = 20; x < 25; x++) { Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } for (var x = 25; x < 100; x++) { Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}"); } tv.SetNeedsDisplay (); tv.Draw (); looksLike = @" 11111│2222│3333│44444444│ │ │ │ │ │ │ │ │ │ │ │ │ "; TestHelpers.AssertDriverContentsAre (looksLike, _output); } [Fact] public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringInsertTile () { TileView tv = GetTileView (20, 10); var myReusableView = new DisposeCounter (); // I want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Equal (0, myReusableView.DisposalCount); // I've changed my mind, I want 3 tiles now tv.InsertTile (0); tv.InsertTile (2); // but I still want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Multiple ( () => Assert.Equal (0, myReusableView.DisposalCount), () => { tv.Dispose (); Assert.True (myReusableView.DisposalCount >= 1); } ); } [Fact] public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount () { TileView tv = GetTileView (20, 10); var myReusableView = new DisposeCounter (); // I want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Equal (0, myReusableView.DisposalCount); // I've changed my mind, I want 3 tiles now tv.RebuildForTileCount (3); // but I still want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Multiple ( () => Assert.Equal (0, myReusableView.DisposalCount), () => { tv.Dispose (); Assert.Equal (1, myReusableView.DisposalCount); } ); } [Theory] [InlineData (0)] [InlineData (1)] public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile (int idx) { TileView tv = GetTileView (20, 10); var myReusableView = new DisposeCounter (); // I want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Equal (0, myReusableView.DisposalCount); tv.RemoveTile (idx); // but I still want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Multiple ( () => Assert.Equal (0, myReusableView.DisposalCount), () => { tv.Dispose (); Assert.True (myReusableView.DisposalCount >= 1); } ); } [Fact] [AutoInitShutdown] public void TestNestedContainer2LeftAnd1Right_RendersNicely () { TileView tileView = GetNestedContainer2Left1Right (false); Assert.Equal (20, tileView.Frame.Width); Assert.Equal (10, tileView.Tiles.ElementAt (0).ContentView.Frame.Width); Assert.Equal (9, tileView.Tiles.ElementAt (1).ContentView.Frame.Width); Assert.IsType (tileView.Tiles.ElementAt (0).ContentView); var left = (TileView)tileView.Tiles.ElementAt (0).ContentView; Assert.Same (left.SuperView, tileView); Assert.Equal (2, left.Tiles.ElementAt (0).ContentView.Subviews.Count); Assert.IsType