using System.Text; using Xunit.Abstractions; namespace Terminal.Gui.ViewTests; public class SubviewTests { private readonly ITestOutputHelper _output; public SubviewTests (ITestOutputHelper output) { _output = output; } [Fact] [TestRespondersDisposed] public void Added_Removed () { var v = new View { Frame = new Rectangle (0, 0, 10, 24) }; var t = new View (); v.Added += (s, e) => { Assert.Same (v.SuperView, e.Parent); Assert.Same (t, e.Parent); Assert.Same (v, e.Child); }; v.Removed += (s, e) => { Assert.Same (t, e.Parent); Assert.Same (v, e.Child); Assert.True (v.SuperView == null); }; t.Add (v); Assert.True (t.Subviews.Count == 1); t.Remove (v); Assert.True (t.Subviews.Count == 0); t.Dispose (); v.Dispose (); } [Fact] [AutoInitShutdown] public void GetTopSuperView_Test () { var v1 = new View (); var fv1 = new FrameView (); fv1.Add (v1); var tf1 = new TextField (); var w1 = new Window (); w1.Add (fv1, tf1); var top1 = new Toplevel (); top1.Add (w1); var v2 = new View (); var fv2 = new FrameView (); fv2.Add (v2); var tf2 = new TextField (); var w2 = new Window (); w2.Add (fv2, tf2); var top2 = new Toplevel (); top2.Add (w2); Assert.Equal (top1, v1.GetTopSuperView ()); Assert.Equal (top2, v2.GetTopSuperView ()); v1.Dispose (); fv1.Dispose (); tf1.Dispose (); w1.Dispose (); top1.Dispose (); v2.Dispose (); fv2.Dispose (); tf2.Dispose (); w2.Dispose (); top2.Dispose (); } [Fact] [TestRespondersDisposed] public void Initialized_Event_Comparing_With_Added_Event () { Application.Init (new FakeDriver ()); var top = new Toplevel { Id = "0" }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 80, 25 var winAddedToTop = new Window { Id = "t", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 78, 23 var v1AddedToWin = new View { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (because Windows has a border) var v2AddedToWin = new View { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (because Windows has a border) var svAddedTov1 = new View { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () }; // Frame: 1, 1, 78, 23 (same as it's superview v1AddedToWin) int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0; winAddedToTop.Added += (s, e) => { Assert.Equal (e.Parent.Frame.Width, winAddedToTop.Frame.Width); Assert.Equal (e.Parent.Frame.Height, winAddedToTop.Frame.Height); }; v1AddedToWin.Added += (s, e) => { Assert.Equal (e.Parent.Frame.Width, v1AddedToWin.Frame.Width); Assert.Equal (e.Parent.Frame.Height, v1AddedToWin.Frame.Height); }; v2AddedToWin.Added += (s, e) => { Assert.Equal (e.Parent.Frame.Width, v2AddedToWin.Frame.Width); Assert.Equal (e.Parent.Frame.Height, v2AddedToWin.Frame.Height); }; svAddedTov1.Added += (s, e) => { Assert.Equal (e.Parent.Frame.Width, svAddedTov1.Frame.Width); Assert.Equal (e.Parent.Frame.Height, svAddedTov1.Frame.Height); }; top.Initialized += (s, e) => { tc++; Assert.Equal (1, tc); Assert.Equal (1, wc); Assert.Equal (1, v1c); Assert.Equal (1, v2c); Assert.Equal (1, sv1c); Assert.True (top.CanFocus); Assert.True (winAddedToTop.CanFocus); Assert.False (v1AddedToWin.CanFocus); Assert.False (v2AddedToWin.CanFocus); Assert.False (svAddedTov1.CanFocus); Application.Refresh (); }; winAddedToTop.Initialized += (s, e) => { wc++; Assert.Equal (top.Viewport.Width, winAddedToTop.Frame.Width); Assert.Equal (top.Viewport.Height, winAddedToTop.Frame.Height); }; v1AddedToWin.Initialized += (s, e) => { v1c++; // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25 // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken. // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Viewport // as it is a subview of winAddedToTop, which has a border! //Assert.Equal (top.Viewport.Width, v1AddedToWin.Frame.Width); //Assert.Equal (top.Viewport.Height, v1AddedToWin.Frame.Height); }; v2AddedToWin.Initialized += (s, e) => { v2c++; // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25 // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken. // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Viewport // as it is a subview of winAddedToTop, which has a border! //Assert.Equal (top.Viewport.Width, v2AddedToWin.Frame.Width); //Assert.Equal (top.Viewport.Height, v2AddedToWin.Frame.Height); }; svAddedTov1.Initialized += (s, e) => { sv1c++; // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25 // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken. // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Viewport // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of // winAddedToTop, which has a border! //Assert.Equal (top.Viewport.Width, svAddedTov1.Frame.Width); //Assert.Equal (top.Viewport.Height, svAddedTov1.Frame.Height); Assert.False (svAddedTov1.CanFocus); Assert.Throws (() => svAddedTov1.CanFocus = true); Assert.False (svAddedTov1.CanFocus); }; v1AddedToWin.Add (svAddedTov1); winAddedToTop.Add (v1AddedToWin, v2AddedToWin); top.Add (winAddedToTop); Application.Iteration += (s, a) => { Application.Refresh (); top.Running = false; }; Application.Run (top); top.Dispose (); Application.Shutdown (); Assert.Equal (1, tc); Assert.Equal (1, wc); Assert.Equal (1, v1c); Assert.Equal (1, v2c); Assert.Equal (1, sv1c); Assert.True (top.CanFocus); Assert.True (winAddedToTop.CanFocus); Assert.False (v1AddedToWin.CanFocus); Assert.False (v2AddedToWin.CanFocus); Assert.False (svAddedTov1.CanFocus); v1AddedToWin.CanFocus = true; Assert.False (svAddedTov1.CanFocus); // False because sv1 was disposed and it isn't a subview of v1. } [Fact] [TestRespondersDisposed] public void Initialized_Event_Will_Be_Invoked_When_Added_Dynamically () { Application.Init (new FakeDriver ()); var t = new Toplevel { Id = "0" }; var w = new Window { Id = "t", Width = Dim.Fill (), Height = Dim.Fill () }; var v1 = new View { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () }; var v2 = new View { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () }; int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0; t.Initialized += (s, e) => { tc++; Assert.Equal (1, tc); Assert.Equal (1, wc); Assert.Equal (1, v1c); Assert.Equal (1, v2c); Assert.Equal (0, sv1c); // Added after t in the Application.Iteration. Assert.True (t.CanFocus); Assert.True (w.CanFocus); Assert.False (v1.CanFocus); Assert.False (v2.CanFocus); Application.Refresh (); }; w.Initialized += (s, e) => { wc++; Assert.Equal (t.Viewport.Width, w.Frame.Width); Assert.Equal (t.Viewport.Height, w.Frame.Height); }; v1.Initialized += (s, e) => { v1c++; //Assert.Equal (t.Viewport.Width, v1.Frame.Width); //Assert.Equal (t.Viewport.Height, v1.Frame.Height); }; v2.Initialized += (s, e) => { v2c++; //Assert.Equal (t.Viewport.Width, v2.Frame.Width); //Assert.Equal (t.Viewport.Height, v2.Frame.Height); }; w.Add (v1, v2); t.Add (w); Application.Iteration += (s, a) => { var sv1 = new View { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () }; sv1.Initialized += (s, e) => { sv1c++; Assert.NotEqual (t.Frame.Width, sv1.Frame.Width); Assert.NotEqual (t.Frame.Height, sv1.Frame.Height); Assert.False (sv1.CanFocus); Assert.Throws (() => sv1.CanFocus = true); Assert.False (sv1.CanFocus); }; v1.Add (sv1); Application.Refresh (); t.Running = false; }; Application.Run (t); t.Dispose (); Application.Shutdown (); Assert.Equal (1, tc); Assert.Equal (1, wc); Assert.Equal (1, v1c); Assert.Equal (1, v2c); Assert.Equal (1, sv1c); Assert.True (t.CanFocus); Assert.True (w.CanFocus); Assert.False (v1.CanFocus); Assert.False (v2.CanFocus); } [Fact] [TestRespondersDisposed] public void IsAdded_Added_Removed () { var top = new Toplevel (); var view = new View (); Assert.False (view.IsAdded); top.Add (view); Assert.True (view.IsAdded); top.Remove (view); Assert.False (view.IsAdded); top.Dispose (); view.Dispose (); } // TODO: Consider a feature that will change the ContentSize to fit the subviews. [Fact] public void Add_Does_Not_Impact_ContentSize () { var view = new View (); view.SetContentSize (new Size (1, 1)); var subview = new View () { X = 10, Y = 10 }; Assert.Equal (new Size (1, 1), view.GetContentSize ()); view.Add (subview); Assert.Equal (new Size (1, 1), view.GetContentSize ()); } [Fact] public void Remove_Does_Not_Impact_ContentSize () { var view = new View (); view.SetContentSize (new Size (1, 1)); var subview = new View () { X = 10, Y = 10 }; Assert.Equal (new Size (1, 1), view.GetContentSize ()); view.Add (subview); Assert.Equal (new Size (1, 1), view.GetContentSize ()); view.SetContentSize (new Size (5, 5)); Assert.Equal (new Size (5, 5), view.GetContentSize ()); view.Remove (subview); Assert.Equal (new Size (5, 5), view.GetContentSize ()); } }