diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs index dc0168c4e..bd9cac432 100644 --- a/UnitTests/ApplicationTests.cs +++ b/UnitTests/ApplicationTests.cs @@ -372,5 +372,609 @@ namespace Terminal.Gui.Core { // Shutdown must be called to safely clean up Application if Init has been called Application.Shutdown (); } + + [Fact] + public void Application_RequestStop_With_Params_On_A_Not_MdiContainer_Always_Use_The_Application_Current () + { + Init (); + + var top1 = new Toplevel (); + var top2 = new Toplevel (); + var top3 = new Window (); + var top4 = new Window (); + var d = new Dialog (); + + // top1, top2, top3, d1 = 4 + var iterations = 4; + + top1.Ready += () => { + Assert.Null (Application.MdiChildes); + Application.Run (top2); + }; + top2.Ready += () => { + Assert.Null (Application.MdiChildes); + Application.Run (top3); + }; + top3.Ready += () => { + Assert.Null (Application.MdiChildes); + Application.Run (top4); + }; + top4.Ready += () => { + Assert.Null (Application.MdiChildes); + Application.Run (d); + }; + + d.Ready += () => { + Assert.Null (Application.MdiChildes); + // This will close the d because on a not MdiContainer the Application.Current it always used. + Application.RequestStop (top1); + Assert.True (Application.Current == d); + }; + + d.Closed += (e) => Application.RequestStop (top1); + + Application.Iteration += () => { + Assert.Null (Application.MdiChildes); + if (iterations == 4) { + Assert.True (Application.Current == d); + } else if (iterations == 3) { + Assert.True (Application.Current == top4); + } else if (iterations == 2) { + Assert.True (Application.Current == top3); + } else if (iterations == 1) { + Assert.True (Application.Current == top2); + } else { + Assert.True (Application.Current == top1); + } + Application.RequestStop (top1); + iterations--; + }; + + Application.Run (top1); + + Assert.Null (Application.MdiChildes); + + Application.Shutdown (); + } + + class Mdi : Toplevel { + public Mdi () + { + IsMdiContainer = true; + } + } + + [Fact] + public void MdiContainer_With_Toplevel_RequestStop_Balanced () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d = new Dialog (); + + // MdiChild = c1, c2, c3 + // d1 = 1 + var iterations = 4; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d); + }; + + // More easy because the Mdi Container handles all at once + d.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + // This will not close the MdiContainer because d is a modal toplevel and will be closed. + mdi.RequestStop (); + }; + + // Now this will close the MdiContainer propagating through the MdiChildes. + d.Closed += (e) => { + mdi.RequestStop (); + }; + + Application.Iteration += () => { + if (iterations == 4) { + // The Dialog was not closed before and will be closed now. + Assert.True (Application.Current == d); + Assert.False (d.Running); + } else { + Assert.Equal (iterations, Application.MdiChildes.Count); + for (int i = 0; i < iterations; i++) { + Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id); + } + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void MdiContainer_With_Application_RequestStop_MdiTop_With_Params () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d = new Dialog (); + + // MdiChild = c1, c2, c3 + // d1 = 1 + var iterations = 4; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d); + }; + + // Also easy because the Mdi Container handles all at once + d.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + // This will not close the MdiContainer because d is a modal toplevel + Application.RequestStop (mdi); + }; + + // Now this will close the MdiContainer propagating through the MdiChildes. + d.Closed += (e) => Application.RequestStop (mdi); + + Application.Iteration += () => { + if (iterations == 4) { + // The Dialog was not closed before and will be closed now. + Assert.True (Application.Current == d); + Assert.False (d.Running); + } else { + Assert.Equal (iterations, Application.MdiChildes.Count); + for (int i = 0; i < iterations; i++) { + Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id); + } + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void MdiContainer_With_Application_RequestStop_MdiTop_Without_Params () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d = new Dialog (); + + // MdiChild = c1, c2, c3 = 3 + // d1 = 1 + var iterations = 4; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d); + }; + + //More harder because it's sequential. + d.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + // Close the Dialog + Application.RequestStop (); + }; + + // Now this will close the MdiContainer propagating through the MdiChildes. + d.Closed += (e) => Application.RequestStop (mdi); + + Application.Iteration += () => { + if (iterations == 4) { + // The Dialog still is the current top and we can't request stop to MdiContainer + // because we are not using parameter calls. + Assert.True (Application.Current == d); + Assert.False (d.Running); + } else { + Assert.Equal (iterations, Application.MdiChildes.Count); + for (int i = 0; i < iterations; i++) { + Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id); + } + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void IsMdiChild_Testing () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d = new Dialog (); + + Application.Iteration += () => { + Assert.False (mdi.IsMdiChild); + Assert.True (c1.IsMdiChild); + Assert.True (c2.IsMdiChild); + Assert.True (c3.IsMdiChild); + Assert.False (d.IsMdiChild); + + mdi.RequestStop (); + }; + + Application.Run (mdi); + + Application.Shutdown (); + } + + [Fact] + public void Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d1 = new Dialog (); + var d2 = new Dialog (); + + // MdiChild = c1, c2, c3 = 3 + // d1, d2 = 2 + var iterations = 5; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d1); + }; + d1.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d2); + }; + + d2.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Assert.True (Application.Current == d2); + Assert.True (Application.Current.Running); + // Trying to close the Dialog1 + d1.RequestStop (); + }; + + // Now this will close the MdiContainer propagating through the MdiChildes. + d1.Closed += (e) => { + Assert.True (Application.Current == d1); + Assert.False (Application.Current.Running); + mdi.RequestStop (); + }; + + Application.Iteration += () => { + if (iterations == 5) { + // The Dialog2 still is the current top and we can't request stop to MdiContainer + // because Dialog2 and Dialog1 must be closed first. + // Dialog2 will be closed in this iteration. + Assert.True (Application.Current == d2); + Assert.False (Application.Current.Running); + Assert.False (d1.Running); + } else if (iterations == 4) { + // Dialog1 will be closed in this iteration. + Assert.True (Application.Current == d1); + Assert.False (Application.Current.Running); + } else { + Assert.Equal (iterations, Application.MdiChildes.Count); + for (int i = 0; i < iterations; i++) { + Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id); + } + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + var d1 = new Dialog (); + var c4 = new Toplevel (); + + // MdiChild = c1, c2, c3, c4 = 4 + // d1 = 1 + var iterations = 5; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (d1); + }; + d1.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + Application.Run (c4); + }; + + c4.Ready += () => { + Assert.Equal (4, Application.MdiChildes.Count); + // Trying to close the Dialog1 + d1.RequestStop (); + }; + + // Now this will close the MdiContainer propagating through the MdiChildes. + d1.Closed += (e) => { + mdi.RequestStop (); + }; + + Application.Iteration += () => { + if (iterations == 5) { + // The Dialog2 still is the current top and we can't request stop to MdiContainer + // because Dialog2 and Dialog1 must be closed first. + // Using request stop here will call the Dialog again without need + Assert.True (Application.Current == d1); + Assert.False (Application.Current.Running); + Assert.True (c4.Running); + } else { + Assert.Equal (iterations, Application.MdiChildes.Count); + for (int i = 0; i < iterations; i++) { + Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (), + Application.MdiChildes [i].Id); + } + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False () + { + Init (); + + var mdi = new Mdi (); + var c1 = new Toplevel (); + var c2 = new Window (); + var c3 = new Window (); + + // MdiChild = c1, c2, c3 + var iterations = 3; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (c1); + }; + c1.Ready += () => { + Assert.Single (Application.MdiChildes); + Application.Run (c2); + }; + c2.Ready += () => { + Assert.Equal (2, Application.MdiChildes.Count); + Application.Run (c3); + }; + c3.Ready += () => { + Assert.Equal (3, Application.MdiChildes.Count); + c3.RequestStop (); + c1.RequestStop (); + }; + // Now this will close the MdiContainer propagating through the MdiChildes. + c1.Closed += (e) => { + mdi.RequestStop (); + }; + Application.Iteration += () => { + if (iterations == 3) { + // The Current still is c3 because Current.Running is false. + Assert.True (Application.Current == c3); + Assert.False (Application.Current.Running); + // But the childes order were reorder by Running = false + Assert.True (Application.MdiChildes [0] == c3); + Assert.True (Application.MdiChildes [1] == c1); + Assert.True (Application.MdiChildes [^1] == c2); + } else if (iterations == 2) { + // The Current is c1 and Current.Running is false. + Assert.True (Application.Current == c1); + Assert.False (Application.Current.Running); + Assert.True (Application.MdiChildes [0] == c1); + Assert.True (Application.MdiChildes [^1] == c2); + } else if (iterations == 1) { + // The Current is c2 and Current.Running is false. + Assert.True (Application.Current == c2); + Assert.False (Application.Current.Running); + Assert.True (Application.MdiChildes [^1] == c2); + } else { + // The Current is mdi. + Assert.True (Application.Current == mdi); + Assert.Empty (Application.MdiChildes); + } + iterations--; + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } + + [Fact] + public void MdiContainer_Throws_If_More_Than_One () + { + Init (); + + var mdi = new Mdi (); + var mdi2 = new Mdi (); + + mdi.Ready += () => { + Assert.Throws (() => Application.Run (mdi2)); + mdi.RequestStop (); + }; + + Application.Run (mdi); + + Application.Shutdown (); + } + + [Fact] + public void MdiContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly () + { + Init (); + + var mdi = new Mdi (); + var logger = new Toplevel (); + + var iterations = 1; // The logger + var running = true; + var stageCompleted = true; + var allStageClosed = false; + var mdiRequestStop = false; + + mdi.Ready += () => { + Assert.Empty (Application.MdiChildes); + Application.Run (logger); + }; + + logger.Ready += () => Assert.Single (Application.MdiChildes); + + Application.Iteration += () => { + if (stageCompleted && running) { + stageCompleted = false; + var stage = new Window () { Modal = true }; + + stage.Ready += () => { + Assert.Equal (iterations, Application.MdiChildes.Count); + stage.RequestStop (); + }; + + stage.Closed += (_) => { + if (iterations == 11) { + allStageClosed = true; + } + Assert.Equal (iterations, Application.MdiChildes.Count); + if (running) { + stageCompleted = true; + + var rpt = new Window (); + + rpt.Ready += () => { + iterations++; + Assert.Equal (iterations, Application.MdiChildes.Count); + }; + + Application.Run (rpt); + } + }; + + Application.Run (stage); + + } else if (iterations == 11 && running) { + running = false; + Assert.Equal (iterations, Application.MdiChildes.Count); + + } else if (!mdiRequestStop && running && !allStageClosed) { + Assert.Equal (iterations, Application.MdiChildes.Count); + + } else if (!mdiRequestStop && !running && allStageClosed) { + Assert.Equal (iterations, Application.MdiChildes.Count); + mdiRequestStop = true; + mdi.RequestStop (); + } else { + Assert.Empty (Application.MdiChildes); + } + }; + + Application.Run (mdi); + + Assert.Empty (Application.MdiChildes); + + Application.Shutdown (); + } } } diff --git a/UnitTests/AssemblyInfo.cs b/UnitTests/AssemblyInfo.cs index f4b657580..1278f5dea 100644 --- a/UnitTests/AssemblyInfo.cs +++ b/UnitTests/AssemblyInfo.cs @@ -7,7 +7,7 @@ using Xunit; // Since Application is a singleton we can't run tests in parallel [assembly: CollectionBehavior (DisableTestParallelization = true)] -// This class enables test functions annotaed with the [AutoInitShutdown] attribute to +// This class enables test functions annotated with the [AutoInitShutdown] attribute to // automatically call Application.Init before called and Application.Shutdown after // // This is necessary because a) Application is a singleton and Init/Shutdown must be called diff --git a/UnitTests/PosTests.cs b/UnitTests/PosTests.cs index 73404bde0..77e1b382e 100644 --- a/UnitTests/PosTests.cs +++ b/UnitTests/PosTests.cs @@ -296,37 +296,43 @@ namespace Terminal.Gui.Core { var app = setup (); app.button.Y = Pos.Left (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); app = setup (); app.button.Y = Pos.X (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); app = setup (); app.button.Y = Pos.Top (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); app = setup (); app.button.Y = Pos.Y (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); app = setup (); app.button.Y = Pos.Bottom (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); app = setup (); app.button.Y = Pos.Right (app.win); rs = Application.Begin (Application.Top); - Application.Run (); + // If Application.RunState is used then we must use Application.RunLoop with the rs parameter + Application.RunLoop (rs); cleanup (rs); } diff --git a/UnitTests/ScenarioTests.cs b/UnitTests/ScenarioTests.cs index 689e4863c..03b0372c8 100644 --- a/UnitTests/ScenarioTests.cs +++ b/UnitTests/ScenarioTests.cs @@ -72,10 +72,12 @@ namespace Terminal.Gui { var scenario = (Scenario)Activator.CreateInstance (scenarioClass); scenario.Init (Application.Top, Colors.Base); scenario.Setup (); - var rs = Application.Begin (Application.Top); + // There is no need to call Application.Begin because Init already creates the Application.Top + // If Application.RunState is used then the Application.RunLoop must also be used instead Application.Run. + //var rs = Application.Begin (Application.Top); scenario.Run (); - Application.End (rs); + //Application.End (rs); // Shutdown must be called to safely clean up Application if Init has been called Application.Shutdown (); @@ -100,7 +102,7 @@ namespace Terminal.Gui { Assert.NotEmpty (scenarioClasses); var item = scenarioClasses.FindIndex (t => Scenario.ScenarioMetadata.GetName (t).Equals ("Generic", StringComparison.OrdinalIgnoreCase)); - var scenarioClass = scenarioClasses[item]; + var scenarioClass = scenarioClasses [item]; // Setup some fake keypresses // Passing empty string will cause just a ctrl-q to be fired int stackSize = CreateInput (""); @@ -132,10 +134,12 @@ namespace Terminal.Gui { var scenario = (Scenario)Activator.CreateInstance (scenarioClass); scenario.Init (Application.Top, Colors.Base); scenario.Setup (); - var rs = Application.Begin (Application.Top); + // There is no need to call Application.Begin because Init already creates the Application.Top + // If Application.RunState is used then the Application.RunLoop must also be used instead Application.Run. + //var rs = Application.Begin (Application.Top); scenario.Run (); - Application.End (rs); + //Application.End (rs); Assert.Equal (0, abortCount); // # of key up events should match # of iterations diff --git a/UnitTests/StackExtensionsTests.cs b/UnitTests/StackExtensionsTests.cs new file mode 100644 index 000000000..fb61b1334 --- /dev/null +++ b/UnitTests/StackExtensionsTests.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using Xunit; + +namespace Terminal.Gui.Core { + public class StackExtensionsTests { + [Fact] + public void Stack_Toplevels_CreateToplevels () + { + Stack toplevels = CreateToplevels (); + + int index = toplevels.Count - 1; + foreach (var top in toplevels) { + if (top.GetType () == typeof (Toplevel)) { + Assert.Equal ("Top", top.Id); + } else { + Assert.Equal ($"w{index}", top.Id); + } + index--; + } + + var tops = toplevels.ToArray (); + + Assert.Equal ("w4", tops [0].Id); + Assert.Equal ("w3", tops [1].Id); + Assert.Equal ("w2", tops [2].Id); + Assert.Equal ("w1", tops [3].Id); + Assert.Equal ("Top", tops [^1].Id); + } + + [Fact] + public void Stack_Toplevels_Replace () + { + Stack toplevels = CreateToplevels (); + + var valueToReplace = new Window () { Id = "w1" }; + var valueToReplaceWith = new Window () { Id = "new" }; + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + + toplevels.Replace (valueToReplace, valueToReplaceWith, comparer); + + var tops = toplevels.ToArray (); + + Assert.Equal ("w4", tops [0].Id); + Assert.Equal ("w3", tops [1].Id); + Assert.Equal ("w2", tops [2].Id); + Assert.Equal ("new", tops [3].Id); + Assert.Equal ("Top", tops [^1].Id); + } + + [Fact] + public void Stack_Toplevels_Swap () + { + Stack toplevels = CreateToplevels (); + + var valueToSwapFrom = new Window () { Id = "w3" }; + var valueToSwapTo = new Window () { Id = "w1" }; + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + toplevels.Swap (valueToSwapFrom, valueToSwapTo, comparer); + + var tops = toplevels.ToArray (); + + Assert.Equal ("w4", tops [0].Id); + Assert.Equal ("w1", tops [1].Id); + Assert.Equal ("w2", tops [2].Id); + Assert.Equal ("w3", tops [3].Id); + Assert.Equal ("Top", tops [^1].Id); + } + + [Fact] + public void Stack_Toplevels_MoveNext () + { + Stack toplevels = CreateToplevels (); + + toplevels.MoveNext (); + + var tops = toplevels.ToArray (); + + Assert.Equal ("w3", tops [0].Id); + Assert.Equal ("w2", tops [1].Id); + Assert.Equal ("w1", tops [2].Id); + Assert.Equal ("Top", tops [3].Id); + Assert.Equal ("w4", tops [^1].Id); + } + + [Fact] + public void Stack_Toplevels_MovePrevious () + { + Stack toplevels = CreateToplevels (); + + toplevels.MovePrevious (); + + var tops = toplevels.ToArray (); + + Assert.Equal ("Top", tops [0].Id); + Assert.Equal ("w4", tops [1].Id); + Assert.Equal ("w3", tops [2].Id); + Assert.Equal ("w2", tops [3].Id); + Assert.Equal ("w1", tops [^1].Id); + } + + [Fact] + public void ToplevelEqualityComparer_GetHashCode () + { + Stack toplevels = CreateToplevels (); + + // Only allows unique keys + HashSet hCodes = new HashSet (); + + foreach (var top in toplevels) { + Assert.True (hCodes.Add (top.GetHashCode ())); + } + } + + [Fact] + public void Stack_Toplevels_FindDuplicates () + { + Stack toplevels = CreateToplevels (); + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + + toplevels.Push (new Toplevel () { Id = "w4" }); + toplevels.Push (new Toplevel () { Id = "w1" }); + + var dup = toplevels.FindDuplicates (comparer).ToArray (); + + Assert.Equal ("w4", dup [0].Id); + Assert.Equal ("w1", dup [^1].Id); + } + + [Fact] + public void Stack_Toplevels_Contains () + { + Stack toplevels = CreateToplevels (); + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + + Assert.True (toplevels.Contains (new Window () { Id = "w2" }, comparer)); + Assert.False (toplevels.Contains (new Toplevel () { Id = "top2" }, comparer)); + } + + [Fact] + public void Stack_Toplevels_MoveTo () + { + Stack toplevels = CreateToplevels (); + + var valueToMove = new Window () { Id = "w1" }; + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + + toplevels.MoveTo (valueToMove, 1, comparer); + + var tops = toplevels.ToArray (); + + Assert.Equal ("w4", tops [0].Id); + Assert.Equal ("w1", tops [1].Id); + Assert.Equal ("w3", tops [2].Id); + Assert.Equal ("w2", tops [3].Id); + Assert.Equal ("Top", tops [^1].Id); + } + + [Fact] + public void Stack_Toplevels_MoveTo_From_Last_To_Top () + { + Stack toplevels = CreateToplevels (); + + var valueToMove = new Window () { Id = "Top" }; + ToplevelEqualityComparer comparer = new ToplevelEqualityComparer (); + + toplevels.MoveTo (valueToMove, 0, comparer); + + var tops = toplevels.ToArray (); + + Assert.Equal ("Top", tops [0].Id); + Assert.Equal ("w4", tops [1].Id); + Assert.Equal ("w3", tops [2].Id); + Assert.Equal ("w2", tops [3].Id); + Assert.Equal ("w1", tops [^1].Id); + } + + + private Stack CreateToplevels () + { + Stack toplevels = new Stack (); + + toplevels.Push (new Toplevel () { Id = "Top" }); + toplevels.Push (new Window () { Id = "w1" }); + toplevels.Push (new Window () { Id = "w2" }); + toplevels.Push (new Window () { Id = "w3" }); + toplevels.Push (new Window () { Id = "w4" }); + + return toplevels; + } + } +} diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs index d6abee6d2..cd4b6a52f 100644 --- a/UnitTests/ViewTests.cs +++ b/UnitTests/ViewTests.cs @@ -1332,5 +1332,43 @@ namespace Terminal.Gui.Views { Assert.True (label.AutoSize); Assert.Equal ("{X=0,Y=0,Width=28,Height=2}", label.Bounds.ToString ()); } + + [Theory] + [InlineData (1)] + [InlineData (2)] + [InlineData (3)] + public void LabelChangeText_RendersCorrectly_Constructors (int choice) + { + var driver = new FakeDriver (); + Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true))); + + try { + // Create a label with a short text + Label lbl; + var text = "test"; + + if (choice == 1) { + // An object initializer should call the default constructor. + lbl = new Label { Text = text }; + } else if (choice == 2) { + // Calling the default constructor followed by the object initializer. + lbl = new Label () { Text = text }; + } else { + // Calling the Text constructor. + lbl = new Label (text); + } + lbl.ColorScheme = new ColorScheme (); + lbl.Redraw (lbl.Bounds); + + // should have the initial text + Assert.Equal ('t', driver.Contents [0, 0, 0]); + Assert.Equal ('e', driver.Contents [0, 1, 0]); + Assert.Equal ('s', driver.Contents [0, 2, 0]); + Assert.Equal ('t', driver.Contents [0, 3, 0]); + Assert.Equal (' ', driver.Contents [0, 4, 0]); + } finally { + Application.Shutdown (); + } + } } }