using System; using System.ComponentModel; using System.Linq; using Xunit; using Xunit.Abstractions; namespace Terminal.Gui.ViewsTests { public class TileViewTests { readonly ITestOutputHelper output; public TileViewTests(ITestOutputHelper output) { this.output = output; } [Fact, AutoInitShutdown] public void TestTileView_Vertical() { var tileView = Get11By3TileView(out var line); tileView.Draw(); string looksLike = @" 11111│22222 11111│22222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect if it is not focused tileView.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_WithBorder() { var tileView = Get11By3TileView(out var line, true); tileView.Draw(); string looksLike = @" ┌────┬────┐ │1111│2222│ └────┴────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect if it is not focused tileView.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_Focused() { var tileView = Get11By3TileView(out var line); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Draw(); string looksLike = @" 11111│22222 11111◊22222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Now while focused move the splitter 1 unit right line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.Draw(); looksLike = @" 111111│2222 111111◊2222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // and 2 to the left line.NewKeyDownEvent(new(KeyCode.CursorLeft)); line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.Draw(); looksLike = @" 1111│222222 1111◊222222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_Focused_WithBorder() { var tileView = Get11By3TileView(out var line, true); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Draw(); string looksLike = @" ┌────┬────┐ │1111◊2222│ └────┴────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Now while focused move the splitter 1 unit right line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.Draw(); looksLike = @" ┌─────┬───┐ │11111◊222│ └─────┴───┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); // and 2 to the left line.NewKeyDownEvent(new(KeyCode.CursorLeft)); line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.Draw(); looksLike = @" ┌───┬─────┐ │111◊22222│ └───┴─────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_Focused_50PercentSplit() { var tileView = Get11By3TileView(out var line); tileView.SetSplitterPos(0, Pos.Percent(50)); Assert.IsType(tileView.SplitterDistances.ElementAt(0)); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Draw(); string looksLike = @" 11111│22222 11111◊22222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Now while focused move the splitter 1 unit right line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.Draw(); looksLike = @" 111111│2222 111111◊2222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Even when moving the splitter location it should stay a Percentage based one Assert.IsType(tileView.SplitterDistances.ElementAt(0)); // and 2 to the left line.NewKeyDownEvent(new(KeyCode.CursorLeft)); line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.Draw(); looksLike = @" 1111│222222 1111◊222222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Even when moving the splitter location it should stay a Percentage based one Assert.IsType(tileView.SplitterDistances.ElementAt(0)); } [Fact, AutoInitShutdown] public void TestTileView_Horizontal() { var tileView = Get11By3TileView(out var line); tileView.Orientation = Orientation.Horizontal; tileView.Draw(); string looksLike = @" 11111111111 ─────────── 22222222222"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect if it is not focused var handled = tileView.NewKeyDownEvent(new(KeyCode.CursorDown)); Assert.False(handled); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_View1MinSize_Absolute() { var tileView = Get11By3TileView(out var line); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Tiles.ElementAt(0).MinSize = 6; // distance is too small (below 6) Assert.False(tileView.SetSplitterPos(0, 2)); // Should stay where it was originally at (50%) Assert.Equal(Pos.Percent(50), tileView.SplitterDistances.ElementAt(0)); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" 11111│22222 11111◊22222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect because it // would take us below the minimum splitter size line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); // but we can continue to move the splitter right if we want line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" 111111│2222 111111◊2222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder() { var tileView = Get11By3TileView(out var line, true); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Tiles.ElementAt(0).MinSize = 5; // distance is too small (below 5) Assert.False(tileView.SetSplitterPos(0, 2)); // Should stay where it was originally at (50%) Assert.Equal(Pos.Percent(50), tileView.SplitterDistances.ElementAt(0)); tileView.Draw(); // so should ignore the 2 distance and stick to 5 string looksLike = @" ┌────┬────┐ │1111◊2222│ └────┴────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect because it // would take us below the minimum splitter size line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); // but we can continue to move the splitter right if we want line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" ┌─────┬───┐ │11111◊222│ └─────┴───┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_View2MinSize_Absolute() { var tileView = Get11By3TileView(out var line); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Tiles.ElementAt(1).MinSize = 6; // distance leaves too little space for view2 (less than 6 would remain) Assert.False(tileView.SetSplitterPos(0, 8)); // Should stay where it was originally at (50%) Assert.Equal(Pos.Percent(50), tileView.SplitterDistances.ElementAt(0)); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" 11111│22222 11111◊22222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect because it // would take us below the minimum splitter size line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); // but we can continue to move the splitter left if we want line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" 1111│222222 1111◊222222 │ "; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder() { var tileView = Get11By3TileView(out var line, true); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Tiles.ElementAt(1).MinSize = 5; // distance leaves too little space for view2 (less than 5 would remain) Assert.False(tileView.SetSplitterPos(0, 8)); // Should stay where it was originally at (50%) Assert.Equal(Pos.Percent(50), tileView.SplitterDistances.ElementAt(0)); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" ┌────┬────┐ │1111◊2222│ └────┴────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Keyboard movement on splitter should have no effect because it // would take us below the minimum splitter size line.NewKeyDownEvent(new(KeyCode.CursorRight)); tileView.SetNeedsDisplay(); tileView.Draw(); TestHelpers.AssertDriverContentsAre(looksLike, output); // but we can continue to move the splitter left if we want line.NewKeyDownEvent(new(KeyCode.CursorLeft)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" ┌───┬─────┐ │111◊22222│ └───┴─────┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_InsertPanelAtStart() { var tileView = Get11By3TileView(out var line, true); tileView.InsertTile(0); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" ┌──┬───┬──┐ │ │111│22│ └──┴───┴──┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_InsertPanelMiddle() { var tileView = Get11By3TileView(out var line, true); tileView.InsertTile(1); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" ┌──┬───┬──┐ │11│ │22│ └──┴───┴──┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_InsertPanelAtEnd() { var tileView = Get11By3TileView(out var line, true); tileView.InsertTile(2); tileView.Draw(); // so should ignore the 2 distance and stick to 6 string looksLike = @" ┌──┬───┬──┐ │11│222│ │ └──┴───┴──┘"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Horizontal_Focused() { var tileView = Get11By3TileView(out var line); tileView.Orientation = Orientation.Horizontal; tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); Assert.True(line.HasFocus); tileView.Draw(); string looksLike = @" 11111111111 ─────◊───── 22222222222"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Now move splitter line down tileView.NewKeyDownEvent(new(KeyCode.CursorDown)); tileView.Draw(); looksLike = @" 11111111111 11111111111 ─────◊─────"; TestHelpers.AssertDriverContentsAre(looksLike, output); // And 2 up line.NewKeyDownEvent(new(KeyCode.CursorUp)); line.NewKeyDownEvent(new(KeyCode.CursorUp)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" ─────◊───── 22222222222 22222222222"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_Horizontal_View1MinSize_Absolute() { var tileView = Get11By3TileView(out var line); tileView.NewKeyDownEvent(new(tileView.ToggleResizable)); tileView.Orientation = Orientation.Horizontal; tileView.Tiles.ElementAt(0).MinSize = 1; // 0 should not be allowed because it brings us below minimum size of View1 Assert.False(tileView.SetSplitterPos(0, 0)); // position should remain where it was, at 50% Assert.Equal(Pos.Percent(50f), tileView.SplitterDistances.ElementAt(0)); tileView.Draw(); string looksLike = @" 11111111111 ─────◊───── 22222222222"; TestHelpers.AssertDriverContentsAre(looksLike, output); // Now move splitter line down (allowed line.NewKeyDownEvent(new(KeyCode.CursorDown)); tileView.Draw(); looksLike = @" 11111111111 11111111111 ─────◊─────"; TestHelpers.AssertDriverContentsAre(looksLike, output); // And up 2 (only 1 is allowed because of minimum size of 1 on view1) line.NewKeyDownEvent(new(KeyCode.CursorUp)); line.NewKeyDownEvent(new(KeyCode.CursorUp)); tileView.SetNeedsDisplay(); tileView.Draw(); looksLike = @" 11111111111 ─────◊───── 22222222222"; TestHelpers.AssertDriverContentsAre(looksLike, output); } [Fact, AutoInitShutdown] public void TestTileView_CannotSetSplitterPosToFuncEtc() { var tileView = Get11By3TileView(); var ex = Assert.Throws(() => tileView.SetSplitterPos(0, Pos.Right(tileView))); Assert.Equal("Only Percent and Absolute values are supported. Passed value was PosView", ex.Message); ex = Assert.Throws(() => tileView.SetSplitterPos(0, Pos.Function(() => 1))); Assert.Equal("Only Percent and Absolute values are supported. Passed value was PosFunc", ex.Message); // Also not allowed because this results in a PosCombine ex = Assert.Throws(() => tileView.SetSplitterPos(0, Pos.Percent(50) - 1)); Assert.Equal("Only Percent and Absolute values are supported. Passed value was PosCombine", ex.Message); } [Fact, AutoInitShutdown] public void TestNestedContainer2LeftAnd1Right_RendersNicely() { var 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