浏览代码

Added Attributes tests; balanced Application.Init/Shutdown

Charlie Kindel 4 年之前
父节点
当前提交
8d8025329e

+ 2 - 2
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -255,10 +255,10 @@ namespace Terminal.Gui {
 		{
 		}
 
-		int currentAttribute;
+		Attribute currentAttribute;
 		public override void SetAttribute (Attribute c)
 		{
-			currentAttribute = c.Value;
+			currentAttribute = c;
 		}
 
 		Key MapKey (ConsoleKeyInfo keyInfo)

+ 11 - 7
Terminal.Gui/Core/Application.cs

@@ -208,14 +208,18 @@ namespace Terminal.Gui {
 		static void Init (Func<Toplevel> topLevelFactory, ConsoleDriver driver = null, IMainLoopDriver mainLoopDriver = null)
 		{
 			if (_initialized && driver == null) return;
-			
+
+			if (_initialized) {
+				throw new InvalidOperationException ("Init must be bracketed by Shutdown");
+			}
+
 			// Used only for start debugging on Unix.
-//#if DEBUG
-//			while (!System.Diagnostics.Debugger.IsAttached) {
-//				System.Threading.Thread.Sleep (100);
-//			}
-//			System.Diagnostics.Debugger.Break ();
-//#endif
+			//#if DEBUG
+			//			while (!System.Diagnostics.Debugger.IsAttached) {
+			//				System.Threading.Thread.Sleep (100);
+			//			}
+			//			System.Diagnostics.Debugger.Break ();
+			//#endif
 
 			// Reset all class variables (Application is a singleton).
 			ResetState ();

+ 3 - 0
UnitTests/ApplicationTests.cs

@@ -368,6 +368,9 @@ namespace Terminal.Gui.Core {
 			};
 
 			Application.Run (top);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 }

+ 5 - 2
UnitTests/AssemblyInfo.cs

@@ -1,4 +1,7 @@
-using Xunit;
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using Xunit;
 
 // Since Application is a singleton we can't run tests in parallel
-[assembly: CollectionBehavior (DisableTestParallelization = true)]
+[assembly: CollectionBehavior (DisableTestParallelization = true)]

+ 147 - 0
UnitTests/AttributeTests.cs

@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Terminal.Gui;
+using Xunit;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.ConsoleDrivers {
+	public class AttributeTests {
+		[Fact]
+		public void Constuctors_Constuct ()
+		{
+			var driver = new FakeDriver ();
+			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			driver.Init (() => { });
+
+			// Test parameterless constructor
+			var attr = new Attribute ();
+
+			Assert.Equal (default (int), attr.Value);
+			Assert.Equal (default (Color), attr.Foreground);
+			Assert.Equal (default (Color), attr.Background);
+
+			// Test value, foreground, background
+			var value = 42;
+			var fg = new Color ();
+			fg = Color.Red;
+
+			var bg = new Color ();
+			bg = Color.Blue;
+
+			attr = new Attribute (value, fg, bg);
+
+			Assert.Equal (value, attr.Value);
+			Assert.Equal (fg, attr.Foreground);
+			Assert.Equal (bg, attr.Background);
+
+			// value, foreground, background
+			attr = new Attribute (fg, bg);
+
+			Assert.Equal (fg, attr.Foreground);
+			Assert.Equal (bg, attr.Background);
+
+			driver.End ();
+			Application.Shutdown ();
+		}
+
+		[Fact]
+		public void Implicit_Assign ()
+		{
+			var driver = new FakeDriver ();
+			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			driver.Init (() => { });
+
+			var attr = new Attribute ();
+
+			var value = 42;
+			var fg = new Color ();
+			fg = Color.Red;
+
+			var bg = new Color ();
+			bg = Color.Blue;
+
+			// Test converstion to int
+			attr = new Attribute (value, fg, bg);
+			int value_implicit = (int)attr.Value;
+			Assert.Equal (value, value_implicit);
+
+			// Test converstion from int
+			attr = value;
+			Assert.Equal (value, attr.Value);
+
+			driver.End ();
+			Application.Shutdown ();
+		}
+
+		[Fact]
+		public void Make_Asserts_IfNotInit ()
+		{
+			var fg = new Color ();
+			fg = Color.Red;
+
+			var bg = new Color ();
+			bg = Color.Blue;
+
+			Assert.Throws<InvalidOperationException> (() => Attribute.Make (fg, bg));
+		}
+
+		[Fact]
+		public void Make_Creates ()
+		{
+			var driver = new FakeDriver ();
+			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			driver.Init (() => { });
+
+			var fg = new Color ();
+			fg = Color.Red;
+
+			var bg = new Color ();
+			bg = Color.Blue;
+
+			var attr =  Attribute.Make (fg, bg);
+
+			Assert.Equal (fg, attr.Foreground);
+			Assert.Equal (bg, attr.Background);
+
+			driver.End ();
+			Application.Shutdown ();
+		}
+
+		[Fact]
+		public void Get_Asserts_IfNotInit ()
+		{
+			Assert.Throws<InvalidOperationException> (() => Attribute.Get ());
+		}
+
+		[Fact]
+		public void Get_Gets ()
+		{
+			var driver = new FakeDriver ();
+			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			driver.Init (() => { });
+
+			var value = 42;
+			var fg = new Color ();
+			fg = Color.Red;
+
+			var bg = new Color ();
+			bg = Color.Blue;
+
+			var attr = new Attribute (value, fg, bg);
+
+			driver.SetAttribute (attr);
+
+			var ret_attr = Attribute.Get ();
+
+			Assert.Equal (value, ret_attr.Value);
+			Assert.Equal (fg, ret_attr.Foreground);
+			Assert.Equal (bg, ret_attr.Background);
+
+			driver.End ();
+			Application.Shutdown ();
+		}
+	}
+}

+ 18 - 0
UnitTests/ConsoleDriverTests.cs

@@ -23,6 +23,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Assert.Equal (Console.BufferWidth, driver.Cols);
 			Assert.Equal (Console.BufferHeight, driver.Rows);
 			driver.End ();
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -46,6 +49,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Assert.Equal (0, Console.CursorTop);
 			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -67,6 +73,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
 			driver.End ();
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -94,6 +103,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Run ();
 
 			Assert.False (wasKeyPressed);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -133,6 +145,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Run ();
 
 			Assert.Equal ("MockKeyPresses", rText);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -226,6 +241,9 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Run ();
 
 			Assert.Equal (key, lastKey);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 }

+ 7 - 0
UnitTests/DimTests.cs

@@ -636,6 +636,9 @@ namespace Terminal.Gui.Core {
 			Application.Run (top);
 
 			Assert.Equal (20, count);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -693,6 +696,10 @@ namespace Terminal.Gui.Core {
 			Application.Run (top);
 
 			Assert.Equal (0, count);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+
 		}
 	}
 }

+ 71 - 5
UnitTests/GraphViewTests.cs

@@ -355,6 +355,9 @@ namespace Terminal.Gui.Views {
 			var ex = Assert.Throws<Exception>(()=>gv.Redraw (gv.Bounds));
 
 			Assert.Equal ("CellSize cannot be 0", ex.Message);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		
@@ -447,6 +450,9 @@ namespace Terminal.Gui.Views {
 			// The screen space the graph will be rendered into should
 			// not overspill the margins
 			Assert.Equal (new Rect (5, 0, 45, 28), graphScreenBounds);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		/// <summary>
@@ -493,6 +499,9 @@ namespace Terminal.Gui.Views {
 			// The screen space the graph will be rendered into should
 			// not overspill the margins
 			Assert.Equal (new Rect (5, 0, 45, 28), graphScreenBounds);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		private class FakeSeries : ISeries {
@@ -550,6 +559,9 @@ namespace Terminal.Gui.Views {
 			// user passes 1 color only but asks for 5 bars
 			var ex = Assert.Throws<ArgumentException>(()=>new MultiBarSeries(5,7,1,colors));
 			Assert.Equal("Number of colors must match the number of bars (Parameter 'numberOfBarsPerCategory')",ex.Message);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -570,6 +582,9 @@ namespace Terminal.Gui.Views {
 			Assert.Equal(series.SubSeries.ElementAt(0).OverrideBarColor,colors[0]);
 			Assert.Equal(series.SubSeries.ElementAt(1).OverrideBarColor,colors[1]);
 			Assert.Equal(series.SubSeries.ElementAt(2).OverrideBarColor,colors[2]);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -651,6 +666,9 @@ namespace Terminal.Gui.Views {
  ┼──┬M──┬M──┬M──────
    heytherebob  ";
 			GraphViewTests.AssertDriverContentsAre (looksLike, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 
@@ -707,6 +725,9 @@ namespace Terminal.Gui.Views {
 			// Screen position x=2 because bars are drawn every 1f of
 			// graph space and CellSize.X is 0.5f
 			Assert.Contains(2, axisX.LabelPoints);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -757,9 +778,10 @@ namespace Terminal.Gui.Views {
 			Assert.Equal(0,barSeries.BarScreenEnds[0].Y);
 			Assert.Equal(9,barSeries.BarScreenStarts[1].Y);
 			Assert.Equal(0,barSeries.BarScreenEnds[1].Y);
-		}
-
 
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+		}
 
 		[Fact]
 		public void TestOneLongOneShortHorizontalBars_WithOffset(){
@@ -819,6 +841,9 @@ namespace Terminal.Gui.Views {
 			// labels should align with the bars (same screen y axis point)
 			Assert.Contains(4, axisY.LabelPoints);
 			Assert.Contains(1, axisY.LabelPoints);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		private class FakeBarSeries : BarSeries{
@@ -896,6 +921,9 @@ namespace Terminal.Gui.Views {
 
 			Assert.InRange(axis.LabelPoints.Max(),0,49);
 			Assert.InRange(axis.LabelPoints.Min(),0,49);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -916,6 +944,9 @@ namespace Terminal.Gui.Views {
 
 			Assert.InRange(axis.LabelPoints.Max(),0,49);
 			Assert.InRange(axis.LabelPoints.Min(),0,49);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -937,6 +968,9 @@ namespace Terminal.Gui.Views {
 			// Axis lables should not be drawn in the margin
 			Assert.InRange(axis.LabelPoints.Max(),5,49);
 			Assert.InRange(axis.LabelPoints.Min(),5,49);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		#endregion
@@ -965,6 +999,9 @@ namespace Terminal.Gui.Views {
 
 			Assert.InRange(axis.LabelPoints.Max(),0,29);
 			Assert.InRange(axis.LabelPoints.Min(),0,29);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -986,6 +1023,9 @@ namespace Terminal.Gui.Views {
 			// Labels should not be drawn into the axis
 			Assert.InRange(axis.LabelPoints.Max(),0,19);
 			Assert.InRange(axis.LabelPoints.Min(),0,19);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -1006,12 +1046,12 @@ namespace Terminal.Gui.Views {
 
 			Assert.InRange(axis.LabelPoints.Max(),0,29);
 			Assert.InRange(axis.LabelPoints.Min(),0,29);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		#endregion
-
-
-		
 	}
 
 	public class TextAnnotationTests {
@@ -1060,6 +1100,9 @@ namespace Terminal.Gui.Views {
  0    5";
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -1102,6 +1145,9 @@ namespace Terminal.Gui.Views {
  0    5";
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -1130,6 +1176,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -1156,6 +1205,8 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Theory]
@@ -1189,6 +1240,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 
@@ -1221,6 +1275,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -1247,6 +1304,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 
@@ -1286,6 +1346,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected, output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -1315,6 +1378,9 @@ namespace Terminal.Gui.Views {
 
 			GraphViewTests.AssertDriverContentsAre (expected,output);
 
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 

+ 8 - 1
UnitTests/PosTests.cs

@@ -288,6 +288,8 @@ namespace Terminal.Gui.Core {
 			{
 				// Cleanup
 				Application.End (rs);
+				// Shutdown must be called to safely clean up Application if Init has been called
+				Application.Shutdown ();
 			}
 
 			// Test cases:
@@ -326,7 +328,6 @@ namespace Terminal.Gui.Core {
 			rs = Application.Begin (Application.Top);
 			Application.Run ();
 			cleanup (rs);
-
 		}
 
 		[Fact]
@@ -581,6 +582,9 @@ namespace Terminal.Gui.Core {
 			Application.Run (top);
 
 			Assert.Equal (20, count);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -638,6 +642,9 @@ namespace Terminal.Gui.Core {
 			Application.Run (top);
 
 			Assert.Equal (0, count);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 }

+ 6 - 0
UnitTests/ScenarioTests.cs

@@ -77,6 +77,9 @@ namespace Terminal.Gui {
 
 				Application.End (rs);
 
+				// Shutdown must be called to safely clean up Application if Init has been called
+				Application.Shutdown ();
+
 				Assert.Equal (0, abortCount);
 				// # of key up events should match # of iterations
 				Assert.Equal (1, iterations);
@@ -140,6 +143,9 @@ namespace Terminal.Gui {
 			// Using variable in the left side of Assert.Equal/NotEqual give error. Must be used literals values.
 			//Assert.Equal (stackSize, iterations);
 
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+
 #if DEBUG_IDISPOSABLE
 			foreach (var inst in Responder.Instances) {
 				Assert.True (inst.WasDisposed);

+ 60 - 20
UnitTests/ScrollBarViewTests.cs

@@ -1,8 +1,51 @@
 using System;
+using System.Diagnostics;
+using System.Reflection;
 using Xunit;
 
 namespace Terminal.Gui.Views {
 	public class ScrollBarViewTests {
+
+		// This class enables test functions annoated with the [InitShutdown] attribute
+		// to have a function called before the test function is called and after.
+		// 
+		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
+		// as a pair, and b) all unit test functions should be atomic.
+		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+		public class InitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+
+			public override void Before (MethodInfo methodUnderTest)
+			{
+				Debug.WriteLine ($"Before: {methodUnderTest.Name}");
+
+				if (_hostView != null) {
+					throw new InvalidOperationException ("After did not run.");
+				}
+
+				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+				var top = Application.Top;
+
+				ScrollBarViewTests._hostView = new HostView () {
+					Width = Dim.Fill (),
+					Height = Dim.Fill (),
+					Top = 0,
+					Lines = 30,
+					Left = 0,
+					Cols = 100
+				};
+
+				top.Add (ScrollBarViewTests._hostView);
+			}
+
+			public override void After (MethodInfo methodUnderTest)
+			{
+				Debug.WriteLine ($"After: {methodUnderTest.Name}");
+				ScrollBarViewTests._hostView = null;
+				Application.Shutdown ();
+			}
+		}
+
 		public class HostView : View {
 			public int Top { get; set; }
 			public int Lines { get; set; }
@@ -10,27 +53,9 @@ namespace Terminal.Gui.Views {
 			public int Cols { get; set; }
 		}
 
-		private HostView _hostView;
+		private static HostView _hostView;
 		private ScrollBarView _scrollBar;
-		private bool _added;
-
-		public ScrollBarViewTests ()
-		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-
-			var top = Application.Top;
-
-			_hostView = new HostView () {
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-				Top = 0,
-				Lines = 30,
-				Left = 0,
-				Cols = 100
-			};
-
-			top.Add (_hostView);
-		}
+		private  bool _added;
 
 		private void AddHandlers ()
 		{
@@ -80,6 +105,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Hosting_A_Null_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		{
 			Assert.Throws<ArgumentNullException> ("The host parameter can't be null.",
@@ -89,6 +115,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Hosting_A_Null_SuperView_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		{
 			Assert.Throws<ArgumentNullException> ("The host SuperView parameter can't be null.",
@@ -98,6 +125,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Hosting_Two_Vertical_ScrollBarView_Throws_ArgumentException ()
 		{
 			var top = new Toplevel ();
@@ -111,6 +139,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Hosting_Two_Horizontal_ScrollBarView_Throws_ArgumentException ()
 		{
 			var top = new Toplevel ();
@@ -124,6 +153,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Scrolling_With_Default_Constructor_Do_Not_Scroll ()
 		{
 			var sbv = new ScrollBarView {
@@ -134,6 +164,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Hosting_A_View_To_A_ScrollBarView ()
 		{
 			RemoveHandlers ();
@@ -159,6 +190,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void ChangedPosition_Update_The_Hosted_View ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -173,6 +205,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void ChangedPosition_Scrolling ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -199,6 +232,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void ChangedPosition_Negative_Value ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -215,6 +249,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void DrawContent_Update_The_ScrollBarView_Position ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -231,6 +266,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void OtherScrollBarView_Not_Null ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -243,6 +279,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void ShowScrollIndicator_Check ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -254,6 +291,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void KeepContentAlwaysInViewport_True ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -293,6 +331,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void KeepContentAlwaysInViewport_False ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -314,6 +353,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void AutoHideScrollBars_Check ()
 		{
 			Hosting_A_View_To_A_ScrollBarView ();

+ 28 - 0
UnitTests/TabViewTests.cs

@@ -38,6 +38,8 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (2, tv.Tabs.Count);
 			Assert.Equal (tab2, tv.SelectedTab);
+
+			Application.Shutdown ();
 		}
 
 
@@ -55,6 +57,8 @@ namespace Terminal.Gui.Views {
 
 			Assert.Null (tv.SelectedTab);
 			Assert.Equal (0, tv.TabScrollOffset);
+
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -73,6 +77,9 @@ namespace Terminal.Gui.Views {
 			// Asking to show tab2 should automatically move scroll offset accordingly
 			tv.SelectedTab = tab2;
 			Assert.Equal (1, tv.TabScrollOffset);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -98,6 +105,9 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (1, called);
 			Assert.Equal (tab1, oldTab);
 			Assert.Equal (tab2, newTab);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 		[Fact]
 		public void RemoveTab_ChangesSelection ()
@@ -108,6 +118,9 @@ namespace Terminal.Gui.Views {
 			tv.RemoveTab (tab1);
 
 			Assert.Equal (tab2, tv.SelectedTab);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -125,6 +138,9 @@ namespace Terminal.Gui.Views {
 			tv.RemoveTab (tab1);
 
 			Assert.Equal (tab2, tv.SelectedTab);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -137,6 +153,9 @@ namespace Terminal.Gui.Views {
 			tv.RemoveTab (tab2);
 
 			Assert.Null (tv.SelectedTab);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -171,6 +190,9 @@ namespace Terminal.Gui.Views {
 			// even though we go right 2 indexes the event should only be called once
 			Assert.Equal (1, called);
 			Assert.Equal (tab4, tv.SelectedTab);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -187,6 +209,9 @@ namespace Terminal.Gui.Views {
 			tv.AddTab (tab1, false);
 
 			Assert.Equal (2, tv.Tabs.Count);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 
@@ -205,6 +230,9 @@ namespace Terminal.Gui.Views {
 
 			Assert.Equal (tab1, tv.SelectedTab);
 
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+
 		}
 
 		private void InitFakeDriver ()

+ 482 - 471
UnitTests/TableViewTests.cs

@@ -10,503 +10,514 @@ using Xunit.Abstractions;
 
 namespace Terminal.Gui.Views {
 
-	public class TableViewTests 
-	{
+	public class TableViewTests {
 		readonly ITestOutputHelper output;
 
-		public TableViewTests(ITestOutputHelper output)
+		public TableViewTests (ITestOutputHelper output)
 		{
 			this.output = output;
 		}
-	[Fact]
-        public void EnsureValidScrollOffsets_WithNoCells()
-        {
-            var tableView = new TableView();
+		[Fact]
+		public void EnsureValidScrollOffsets_WithNoCells ()
+		{
+			var tableView = new TableView ();
+
+			Assert.Equal (0, tableView.RowOffset);
+			Assert.Equal (0, tableView.ColumnOffset);
+
+			// Set empty table
+			tableView.Table = new DataTable ();
+
+			// Since table has no rows or columns scroll offset should default to 0
+			tableView.EnsureValidScrollOffsets ();
+			Assert.Equal (0, tableView.RowOffset);
+			Assert.Equal (0, tableView.ColumnOffset);
+		}
+
+
+
+		[Fact]
+		public void EnsureValidScrollOffsets_LoadSmallerTable ()
+		{
+			var tableView = new TableView ();
+			tableView.Bounds = new Rect (0, 0, 25, 10);
+
+			Assert.Equal (0, tableView.RowOffset);
+			Assert.Equal (0, tableView.ColumnOffset);
+
+			// Set big table
+			tableView.Table = BuildTable (25, 50);
+
+			// Scroll down and along
+			tableView.RowOffset = 20;
+			tableView.ColumnOffset = 10;
+
+			tableView.EnsureValidScrollOffsets ();
+
+			// The scroll should be valid at the moment
+			Assert.Equal (20, tableView.RowOffset);
+			Assert.Equal (10, tableView.ColumnOffset);
+
+			// Set small table
+			tableView.Table = BuildTable (2, 2);
 
-            Assert.Equal(0,tableView.RowOffset);
-            Assert.Equal(0,tableView.ColumnOffset);
+			// Setting a small table should automatically trigger fixing the scroll offsets to ensure valid cells
+			Assert.Equal (0, tableView.RowOffset);
+			Assert.Equal (0, tableView.ColumnOffset);
 
-            // Set empty table
-            tableView.Table = new DataTable();
 
-            // Since table has no rows or columns scroll offset should default to 0
-            tableView.EnsureValidScrollOffsets();
-            Assert.Equal(0,tableView.RowOffset);
-            Assert.Equal(0,tableView.ColumnOffset);
-        }
-
-
-
-        [Fact]
-        public void EnsureValidScrollOffsets_LoadSmallerTable()
-        {
-            var tableView = new TableView();
-            tableView.Bounds = new Rect(0,0,25,10);
-
-            Assert.Equal(0,tableView.RowOffset);
-            Assert.Equal(0,tableView.ColumnOffset);
-
-            // Set big table
-            tableView.Table = BuildTable(25,50);
-
-            // Scroll down and along
-            tableView.RowOffset = 20;
-            tableView.ColumnOffset = 10;
-
-            tableView.EnsureValidScrollOffsets();
-
-            // The scroll should be valid at the moment
-            Assert.Equal(20,tableView.RowOffset);
-            Assert.Equal(10,tableView.ColumnOffset);
-
-            // Set small table
-            tableView.Table = BuildTable(2,2);
-
-            // Setting a small table should automatically trigger fixing the scroll offsets to ensure valid cells
-            Assert.Equal(0,tableView.RowOffset);
-            Assert.Equal(0,tableView.ColumnOffset);
-
-
-            // Trying to set invalid indexes should not be possible
-            tableView.RowOffset = 20;
-            tableView.ColumnOffset = 10;
-
-            Assert.Equal(1,tableView.RowOffset);
-            Assert.Equal(1,tableView.ColumnOffset);
-        }
-
-        [Fact]
-        public void SelectedCellChanged_NotFiredForSameValue()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50)
-            };
-
-            bool called = false;
-            tableView.SelectedCellChanged += (e)=>{called=true;};
-
-            Assert.Equal(0,tableView.SelectedColumn);
-            Assert.False(called);
-            
-            // Changing value to same as it already was should not raise an event
-            tableView.SelectedColumn = 0;
-
-            Assert.False(called);
-
-            tableView.SelectedColumn = 10;
-            Assert.True(called);
-        }
-
-
-
-        [Fact]
-        public void SelectedCellChanged_SelectedColumnIndexesCorrect()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50)
-            };
-
-            bool called = false;
-            tableView.SelectedCellChanged += (e)=>{
-                called=true;
-                Assert.Equal(0,e.OldCol);
-                Assert.Equal(10,e.NewCol);
-            };
-            
-            tableView.SelectedColumn = 10;
-            Assert.True(called);
-        }
-
-        [Fact]
-        public void SelectedCellChanged_SelectedRowIndexesCorrect()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50)
-            };
-
-            bool called = false;
-            tableView.SelectedCellChanged += (e)=>{
-                called=true;
-                Assert.Equal(0,e.OldRow);
-                Assert.Equal(10,e.NewRow);
-            };
-            
-            tableView.SelectedRow = 10;
-            Assert.True(called);
-        }
-
-        [Fact]
-        public void Test_SumColumnWidth_UnicodeLength()
-        {
-            Assert.Equal(11,"hello there".Sum(c=>Rune.ColumnWidth(c)));
-
-            // Creates a string with the peculiar (french?) r symbol
-            String surrogate = "Les Mise" + Char.ConvertFromUtf32(Int32.Parse("0301", NumberStyles.HexNumber)) + "rables";
-
-            // The unicode width of this string is shorter than the string length! 
-            Assert.Equal(14,surrogate.Sum(c=>Rune.ColumnWidth(c)));
-            Assert.Equal(15,surrogate.Length);
-        }
-
-        [Fact]
-        public void IsSelected_MultiSelectionOn_Vertical()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50),
-                MultiSelect = true
-            };
-
-            // 3 cell vertical selection
-            tableView.SetSelection(1,1,false);
-            tableView.SetSelection(1,3,true);
-
-            Assert.False(tableView.IsSelected(0,0));
-            Assert.False(tableView.IsSelected(1,0));
-            Assert.False(tableView.IsSelected(2,0));
-
-            Assert.False(tableView.IsSelected(0,1));
-            Assert.True(tableView.IsSelected(1,1));
-            Assert.False(tableView.IsSelected(2,1));
-
-            Assert.False(tableView.IsSelected(0,2));
-            Assert.True(tableView.IsSelected(1,2));
-            Assert.False(tableView.IsSelected(2,2));
-
-            Assert.False(tableView.IsSelected(0,3));
-            Assert.True(tableView.IsSelected(1,3));
-            Assert.False(tableView.IsSelected(2,3));
-
-            Assert.False(tableView.IsSelected(0,4));
-            Assert.False(tableView.IsSelected(1,4));
-            Assert.False(tableView.IsSelected(2,4));
-        }
-
-
-        [Fact]
-        public void IsSelected_MultiSelectionOn_Horizontal()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50),
-                MultiSelect = true
-            };
-
-            // 2 cell horizontal selection
-            tableView.SetSelection(1,0,false);
-            tableView.SetSelection(2,0,true);
-
-            Assert.False(tableView.IsSelected(0,0));
-            Assert.True(tableView.IsSelected(1,0));
-            Assert.True(tableView.IsSelected(2,0));
-            Assert.False(tableView.IsSelected(3,0));
-
-            Assert.False(tableView.IsSelected(0,1));
-            Assert.False(tableView.IsSelected(1,1));
-            Assert.False(tableView.IsSelected(2,1));
-            Assert.False(tableView.IsSelected(3,1));
-        }
-
-
-
-        [Fact]
-        public void IsSelected_MultiSelectionOn_BoxSelection()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(25,50),
-                MultiSelect = true
-            };
-
-            // 4 cell horizontal in box 2x2
-            tableView.SetSelection(0,0,false);
-            tableView.SetSelection(1,1,true);
-
-            Assert.True(tableView.IsSelected(0,0));
-            Assert.True(tableView.IsSelected(1,0));
-            Assert.False(tableView.IsSelected(2,0));
-
-            Assert.True(tableView.IsSelected(0,1));
-            Assert.True(tableView.IsSelected(1,1));
-            Assert.False(tableView.IsSelected(2,1));
-
-            Assert.False(tableView.IsSelected(0,2));
-            Assert.False(tableView.IsSelected(1,2));
-            Assert.False(tableView.IsSelected(2,2));
-        }
-
-        [Fact]
-        public void PageDown_ExcludesHeaders()
-        {
+			// Trying to set invalid indexes should not be possible
+			tableView.RowOffset = 20;
+			tableView.ColumnOffset = 10;
+
+			Assert.Equal (1, tableView.RowOffset);
+			Assert.Equal (1, tableView.ColumnOffset);
+		}
+
+		[Fact]
+		public void SelectedCellChanged_NotFiredForSameValue ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50)
+			};
+
+			bool called = false;
+			tableView.SelectedCellChanged += (e) => { called = true; };
+
+			Assert.Equal (0, tableView.SelectedColumn);
+			Assert.False (called);
+
+			// Changing value to same as it already was should not raise an event
+			tableView.SelectedColumn = 0;
+
+			Assert.False (called);
+
+			tableView.SelectedColumn = 10;
+			Assert.True (called);
+		}
+
+
+
+		[Fact]
+		public void SelectedCellChanged_SelectedColumnIndexesCorrect ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50)
+			};
+
+			bool called = false;
+			tableView.SelectedCellChanged += (e) => {
+				called = true;
+				Assert.Equal (0, e.OldCol);
+				Assert.Equal (10, e.NewCol);
+			};
+
+			tableView.SelectedColumn = 10;
+			Assert.True (called);
+		}
+
+		[Fact]
+		public void SelectedCellChanged_SelectedRowIndexesCorrect ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50)
+			};
+
+			bool called = false;
+			tableView.SelectedCellChanged += (e) => {
+				called = true;
+				Assert.Equal (0, e.OldRow);
+				Assert.Equal (10, e.NewRow);
+			};
+
+			tableView.SelectedRow = 10;
+			Assert.True (called);
+		}
+
+		[Fact]
+		public void Test_SumColumnWidth_UnicodeLength ()
+		{
+			Assert.Equal (11, "hello there".Sum (c => Rune.ColumnWidth (c)));
+
+			// Creates a string with the peculiar (french?) r symbol
+			String surrogate = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables";
+
+			// The unicode width of this string is shorter than the string length! 
+			Assert.Equal (14, surrogate.Sum (c => Rune.ColumnWidth (c)));
+			Assert.Equal (15, surrogate.Length);
+		}
+
+		[Fact]
+		public void IsSelected_MultiSelectionOn_Vertical ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50),
+				MultiSelect = true
+			};
+
+			// 3 cell vertical selection
+			tableView.SetSelection (1, 1, false);
+			tableView.SetSelection (1, 3, true);
+
+			Assert.False (tableView.IsSelected (0, 0));
+			Assert.False (tableView.IsSelected (1, 0));
+			Assert.False (tableView.IsSelected (2, 0));
+
+			Assert.False (tableView.IsSelected (0, 1));
+			Assert.True (tableView.IsSelected (1, 1));
+			Assert.False (tableView.IsSelected (2, 1));
+
+			Assert.False (tableView.IsSelected (0, 2));
+			Assert.True (tableView.IsSelected (1, 2));
+			Assert.False (tableView.IsSelected (2, 2));
+
+			Assert.False (tableView.IsSelected (0, 3));
+			Assert.True (tableView.IsSelected (1, 3));
+			Assert.False (tableView.IsSelected (2, 3));
+
+			Assert.False (tableView.IsSelected (0, 4));
+			Assert.False (tableView.IsSelected (1, 4));
+			Assert.False (tableView.IsSelected (2, 4));
+		}
+
+
+		[Fact]
+		public void IsSelected_MultiSelectionOn_Horizontal ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50),
+				MultiSelect = true
+			};
+
+			// 2 cell horizontal selection
+			tableView.SetSelection (1, 0, false);
+			tableView.SetSelection (2, 0, true);
+
+			Assert.False (tableView.IsSelected (0, 0));
+			Assert.True (tableView.IsSelected (1, 0));
+			Assert.True (tableView.IsSelected (2, 0));
+			Assert.False (tableView.IsSelected (3, 0));
+
+			Assert.False (tableView.IsSelected (0, 1));
+			Assert.False (tableView.IsSelected (1, 1));
+			Assert.False (tableView.IsSelected (2, 1));
+			Assert.False (tableView.IsSelected (3, 1));
+		}
+
+
+
+		[Fact]
+		public void IsSelected_MultiSelectionOn_BoxSelection ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50),
+				MultiSelect = true
+			};
+
+			// 4 cell horizontal in box 2x2
+			tableView.SetSelection (0, 0, false);
+			tableView.SetSelection (1, 1, true);
+
+			Assert.True (tableView.IsSelected (0, 0));
+			Assert.True (tableView.IsSelected (1, 0));
+			Assert.False (tableView.IsSelected (2, 0));
+
+			Assert.True (tableView.IsSelected (0, 1));
+			Assert.True (tableView.IsSelected (1, 1));
+			Assert.False (tableView.IsSelected (2, 1));
+
+			Assert.False (tableView.IsSelected (0, 2));
+			Assert.False (tableView.IsSelected (1, 2));
+			Assert.False (tableView.IsSelected (2, 2));
+		}
+
+		[Fact]
+		public void PageDown_ExcludesHeaders ()
+		{
 
 			var driver = new FakeDriver ();
 			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 			driver.Init (() => { });
 
 
-            var tableView = new TableView(){
-                Table = BuildTable(25,50),
-                MultiSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            // Header should take up 2 lines
-            tableView.Style.ShowHorizontalHeaderOverline = false;
-            tableView.Style.ShowHorizontalHeaderUnderline = true;
-            tableView.Style.AlwaysShowHeaders = false;
+			var tableView = new TableView () {
+				Table = BuildTable (25, 50),
+				MultiSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			// Header should take up 2 lines
+			tableView.Style.ShowHorizontalHeaderOverline = false;
+			tableView.Style.ShowHorizontalHeaderUnderline = true;
+			tableView.Style.AlwaysShowHeaders = false;
+
+			Assert.Equal (0, tableView.RowOffset);
+
+			tableView.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ()));
+
+			// window height is 5 rows 2 are header so page down should give 3 new rows
+			Assert.Equal (3, tableView.RowOffset);
+
+			// header is no longer visible so page down should give 5 new rows
+			tableView.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ()));
 
-            Assert.Equal(0,tableView.RowOffset);
+			Assert.Equal (8, tableView.RowOffset);
 
-            tableView.ProcessKey(new KeyEvent(Key.PageDown,new KeyModifiers()));
-
-            // window height is 5 rows 2 are header so page down should give 3 new rows
-            Assert.Equal(3,tableView.RowOffset);
-
-            // header is no longer visible so page down should give 5 new rows
-            tableView.ProcessKey(new KeyEvent(Key.PageDown,new KeyModifiers()));
-            
-            Assert.Equal(8,tableView.RowOffset);
-        }
-
-        [Fact]
-        public void DeleteRow_SelectAll_AdjustsSelectionToPreventOverrun()
-        {
-            // create a 4 by 4 table
-            var tableView = new TableView(){
-                Table = BuildTable(4,4),
-                MultiSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            tableView.SelectAll();
-            Assert.Equal(16,tableView.GetAllSelectedCells().Count());
-
-            // delete one of the columns
-            tableView.Table.Columns.RemoveAt(2);
-
-            // table should now be 3x4
-            Assert.Equal(12,tableView.GetAllSelectedCells().Count());
-
-            // remove a row
-            tableView.Table.Rows.RemoveAt(1);
-
-            // table should now be 3x3
-            Assert.Equal(9,tableView.GetAllSelectedCells().Count());
-        }
-
-
-        [Fact]
-        public void DeleteRow_SelectLastRow_AdjustsSelectionToPreventOverrun()
-        {
-            // create a 4 by 4 table
-            var tableView = new TableView(){
-                Table = BuildTable(4,4),
-                MultiSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            // select the last row
-            tableView.MultiSelectedRegions.Clear();
-            tableView.MultiSelectedRegions.Push(new TableView.TableSelection (new Point(0,3), new Rect(0,3,4,1)));
-
-            Assert.Equal(4,tableView.GetAllSelectedCells().Count());
-
-            // remove a row
-            tableView.Table.Rows.RemoveAt(0);
-
-            tableView.EnsureValidSelection();
-
-            // since the selection no longer exists it should be removed
-            Assert.Empty(tableView.MultiSelectedRegions);
-        }
-
-        [Theory]
-        [InlineData(true)]
-        [InlineData(false)]
-        public void GetAllSelectedCells_SingleCellSelected_ReturnsOne(bool multiSelect)
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(3,3),
-                MultiSelect = multiSelect,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            tableView.SetSelection(1,1,false);
-
-            Assert.Single(tableView.GetAllSelectedCells());
-            Assert.Equal(new Point(1,1),tableView.GetAllSelectedCells().Single());
-        }
-
-
-        [Fact]
-        public void GetAllSelectedCells_SquareSelection_ReturnsFour()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(3,3),
-                MultiSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            // move cursor to 1,1
-            tableView.SetSelection(1,1,false);
-            // spread selection across to 2,2 (e.g. shift+right then shift+down)
-            tableView.SetSelection(2,2,true);
-
-            var selected = tableView.GetAllSelectedCells().ToArray();
-
-            Assert.Equal(4,selected.Length);
-            Assert.Equal(new Point(1,1),selected[0]);
-            Assert.Equal(new Point(2,1),selected[1]);
-            Assert.Equal(new Point(1,2),selected[2]);
-            Assert.Equal(new Point(2,2),selected[3]);
-        }
-        
-
-        [Fact]
-        public void GetAllSelectedCells_SquareSelection_FullRowSelect()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(3,3),
-                MultiSelect = true,
-                FullRowSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            // move cursor to 1,1
-            tableView.SetSelection(1,1,false);
-            // spread selection across to 2,2 (e.g. shift+right then shift+down)
-            tableView.SetSelection(2,2,true);
-
-            var selected = tableView.GetAllSelectedCells().ToArray();
-
-            Assert.Equal(6,selected.Length);
-            Assert.Equal(new Point(0,1),selected[0]);
-            Assert.Equal(new Point(1,1),selected[1]);
-            Assert.Equal(new Point(2,1),selected[2]);
-            Assert.Equal(new Point(0,2),selected[3]);
-            Assert.Equal(new Point(1,2),selected[4]);
-            Assert.Equal(new Point(2,2),selected[5]);
-        }
-        
-
-        [Fact]
-        public void GetAllSelectedCells_TwoIsolatedSelections_ReturnsSix()
-        {
-            var tableView = new TableView(){
-                Table = BuildTable(20,20),
-                MultiSelect = true,
-                Bounds = new Rect(0,0,10,5)
-            };
-
-            /*  
-                    Sets up disconnected selections like:
-
-                    00000000000
-                    01100000000
-                    01100000000
-                    00000001100
-                    00000000000
-            */
-
-            tableView.MultiSelectedRegions.Clear();
-            tableView.MultiSelectedRegions.Push(new TableView.TableSelection(new Point(1,1),new Rect(1,1,2,2)));
-            tableView.MultiSelectedRegions.Push(new TableView.TableSelection (new Point(7,3),new Rect(7,3,2,1)));
-            
-            tableView.SelectedColumn = 8;
-            tableView.SelectedRow = 3;
-
-            var selected = tableView.GetAllSelectedCells().ToArray();
-
-            Assert.Equal(6,selected.Length);
-
-            Assert.Equal(new Point(1,1),selected[0]);
-            Assert.Equal(new Point(2,1),selected[1]);
-            Assert.Equal(new Point(1,2),selected[2]);
-            Assert.Equal(new Point(2,2),selected[3]);
-            Assert.Equal(new Point(7,3),selected[4]);
-            Assert.Equal(new Point(8,3),selected[5]);
-        }
-
-        [Fact]
-        public void TableView_ExpandLastColumn_True()
-        {
-            var tv = SetUpMiniTable();
-            
-            // the thing we are testing
-            tv.Style.ExpandLastColumn = true;
-
-            tv.Redraw(tv.Bounds);
-            
-            string expected = @"
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+		}
+
+		[Fact]
+		public void DeleteRow_SelectAll_AdjustsSelectionToPreventOverrun ()
+		{
+			// create a 4 by 4 table
+			var tableView = new TableView () {
+				Table = BuildTable (4, 4),
+				MultiSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			tableView.SelectAll ();
+			Assert.Equal (16, tableView.GetAllSelectedCells ().Count ());
+
+			// delete one of the columns
+			tableView.Table.Columns.RemoveAt (2);
+
+			// table should now be 3x4
+			Assert.Equal (12, tableView.GetAllSelectedCells ().Count ());
+
+			// remove a row
+			tableView.Table.Rows.RemoveAt (1);
+
+			// table should now be 3x3
+			Assert.Equal (9, tableView.GetAllSelectedCells ().Count ());
+		}
+
+
+		[Fact]
+		public void DeleteRow_SelectLastRow_AdjustsSelectionToPreventOverrun ()
+		{
+			// create a 4 by 4 table
+			var tableView = new TableView () {
+				Table = BuildTable (4, 4),
+				MultiSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			// select the last row
+			tableView.MultiSelectedRegions.Clear ();
+			tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (0, 3), new Rect (0, 3, 4, 1)));
+
+			Assert.Equal (4, tableView.GetAllSelectedCells ().Count ());
+
+			// remove a row
+			tableView.Table.Rows.RemoveAt (0);
+
+			tableView.EnsureValidSelection ();
+
+			// since the selection no longer exists it should be removed
+			Assert.Empty (tableView.MultiSelectedRegions);
+		}
+
+		[Theory]
+		[InlineData (true)]
+		[InlineData (false)]
+		public void GetAllSelectedCells_SingleCellSelected_ReturnsOne (bool multiSelect)
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (3, 3),
+				MultiSelect = multiSelect,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			tableView.SetSelection (1, 1, false);
+
+			Assert.Single (tableView.GetAllSelectedCells ());
+			Assert.Equal (new Point (1, 1), tableView.GetAllSelectedCells ().Single ());
+		}
+
+
+		[Fact]
+		public void GetAllSelectedCells_SquareSelection_ReturnsFour ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (3, 3),
+				MultiSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			// move cursor to 1,1
+			tableView.SetSelection (1, 1, false);
+			// spread selection across to 2,2 (e.g. shift+right then shift+down)
+			tableView.SetSelection (2, 2, true);
+
+			var selected = tableView.GetAllSelectedCells ().ToArray ();
+
+			Assert.Equal (4, selected.Length);
+			Assert.Equal (new Point (1, 1), selected [0]);
+			Assert.Equal (new Point (2, 1), selected [1]);
+			Assert.Equal (new Point (1, 2), selected [2]);
+			Assert.Equal (new Point (2, 2), selected [3]);
+		}
+
+
+		[Fact]
+		public void GetAllSelectedCells_SquareSelection_FullRowSelect ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (3, 3),
+				MultiSelect = true,
+				FullRowSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			// move cursor to 1,1
+			tableView.SetSelection (1, 1, false);
+			// spread selection across to 2,2 (e.g. shift+right then shift+down)
+			tableView.SetSelection (2, 2, true);
+
+			var selected = tableView.GetAllSelectedCells ().ToArray ();
+
+			Assert.Equal (6, selected.Length);
+			Assert.Equal (new Point (0, 1), selected [0]);
+			Assert.Equal (new Point (1, 1), selected [1]);
+			Assert.Equal (new Point (2, 1), selected [2]);
+			Assert.Equal (new Point (0, 2), selected [3]);
+			Assert.Equal (new Point (1, 2), selected [4]);
+			Assert.Equal (new Point (2, 2), selected [5]);
+		}
+
+
+		[Fact]
+		public void GetAllSelectedCells_TwoIsolatedSelections_ReturnsSix ()
+		{
+			var tableView = new TableView () {
+				Table = BuildTable (20, 20),
+				MultiSelect = true,
+				Bounds = new Rect (0, 0, 10, 5)
+			};
+
+			/*  
+				Sets up disconnected selections like:
+
+				00000000000
+				01100000000
+				01100000000
+				00000001100
+				00000000000
+			*/
+
+			tableView.MultiSelectedRegions.Clear ();
+			tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (1, 1), new Rect (1, 1, 2, 2)));
+			tableView.MultiSelectedRegions.Push (new TableView.TableSelection (new Point (7, 3), new Rect (7, 3, 2, 1)));
+
+			tableView.SelectedColumn = 8;
+			tableView.SelectedRow = 3;
+
+			var selected = tableView.GetAllSelectedCells ().ToArray ();
+
+			Assert.Equal (6, selected.Length);
+
+			Assert.Equal (new Point (1, 1), selected [0]);
+			Assert.Equal (new Point (2, 1), selected [1]);
+			Assert.Equal (new Point (1, 2), selected [2]);
+			Assert.Equal (new Point (2, 2), selected [3]);
+			Assert.Equal (new Point (7, 3), selected [4]);
+			Assert.Equal (new Point (8, 3), selected [5]);
+		}
+
+		[Fact]
+		public void TableView_ExpandLastColumn_True ()
+		{
+			var tv = SetUpMiniTable ();
+
+			// the thing we are testing
+			tv.Style.ExpandLastColumn = true;
+
+			tv.Redraw (tv.Bounds);
+
+			string expected = @"
 ┌─┬──────┐
 │A│B     │
 ├─┼──────┤
 │1│2     │
 ";
-            GraphViewTests.AssertDriverContentsAre(expected, output);
-        }
+			GraphViewTests.AssertDriverContentsAre (expected, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+		}
+
 
+		[Fact]
+		public void TableView_ExpandLastColumn_False ()
+		{
+			var tv = SetUpMiniTable ();
+
+			// the thing we are testing
+			tv.Style.ExpandLastColumn = false;
 
-        [Fact]
-        public void TableView_ExpandLastColumn_False()
-        {
-            var tv = SetUpMiniTable();
-            
-            // the thing we are testing
-            tv.Style.ExpandLastColumn = false;
+			tv.Redraw (tv.Bounds);
 
-            tv.Redraw(tv.Bounds);
-            
-            string expected = @"
+			string expected = @"
 ┌─┬─┬────┐
 │A│B│    │
 ├─┼─┼────┤
 │1│2│    │
 ";
-            GraphViewTests.AssertDriverContentsAre(expected, output);
-        }
-
-        [Fact]
-        public void TableView_ExpandLastColumn_False_ExactBounds()
-        {
-            var tv = SetUpMiniTable();
-            
-            // the thing we are testing
-            tv.Style.ExpandLastColumn = false;
-            // width exactly matches the max col widths
-            tv.Bounds = new Rect(0,0,5,4);
-
-            tv.Redraw(tv.Bounds);
-            
-            string expected = @"
+			GraphViewTests.AssertDriverContentsAre (expected, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+		}
+
+		[Fact]
+		public void TableView_ExpandLastColumn_False_ExactBounds ()
+		{
+			var tv = SetUpMiniTable ();
+
+			// the thing we are testing
+			tv.Style.ExpandLastColumn = false;
+			// width exactly matches the max col widths
+			tv.Bounds = new Rect (0, 0, 5, 4);
+
+			tv.Redraw (tv.Bounds);
+
+			string expected = @"
 ┌─┬─┐
 │A│B│
 ├─┼─┤
 │1│2│
 ";
-            GraphViewTests.AssertDriverContentsAre(expected, output);
-        }
+			GraphViewTests.AssertDriverContentsAre (expected, output);
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
+		}
 
 		private TableView SetUpMiniTable ()
 		{
-			
-            var tv = new TableView();
-            tv.Bounds = new Rect(0,0,10,4);
-
-            var dt = new DataTable();
-            var colA = dt.Columns.Add("A");
-            var colB = dt.Columns.Add("B");
-            dt.Rows.Add(1,2);
-
-            tv.Table = dt;
-            tv.Style.GetOrCreateColumnStyle(colA).MinWidth=1;
-            tv.Style.GetOrCreateColumnStyle(colA).MinWidth=1;
-            tv.Style.GetOrCreateColumnStyle(colB).MaxWidth=1;
-            tv.Style.GetOrCreateColumnStyle(colB).MaxWidth=1;
-
-            GraphViewTests.InitFakeDriver();
-            tv.ColorScheme = new ColorScheme(){
-                Normal = Application.Driver.MakeAttribute(Color.White,Color.Black),
-                HotFocus = Application.Driver.MakeAttribute(Color.White,Color.Black)
-                };
-            return tv;
+
+			var tv = new TableView ();
+			tv.Bounds = new Rect (0, 0, 10, 4);
+
+			var dt = new DataTable ();
+			var colA = dt.Columns.Add ("A");
+			var colB = dt.Columns.Add ("B");
+			dt.Rows.Add (1, 2);
+
+			tv.Table = dt;
+			tv.Style.GetOrCreateColumnStyle (colA).MinWidth = 1;
+			tv.Style.GetOrCreateColumnStyle (colA).MinWidth = 1;
+			tv.Style.GetOrCreateColumnStyle (colB).MaxWidth = 1;
+			tv.Style.GetOrCreateColumnStyle (colB).MaxWidth = 1;
+
+			GraphViewTests.InitFakeDriver ();
+			tv.ColorScheme = new ColorScheme () {
+				Normal = Application.Driver.MakeAttribute (Color.White, Color.Black),
+				HotFocus = Application.Driver.MakeAttribute (Color.White, Color.Black)
+			};
+			return tv;
 		}
 
 		/// <summary>
@@ -515,24 +526,24 @@ namespace Terminal.Gui.Views {
 		/// <param name="cols"></param>
 		/// <param name="rows"></param>
 		/// <returns></returns>
-		public static DataTable BuildTable(int cols, int rows)
+		public static DataTable BuildTable (int cols, int rows)
 		{
-			var dt = new DataTable();
+			var dt = new DataTable ();
 
-			for(int c = 0; c < cols; c++) {
-				dt.Columns.Add("Col"+c);
+			for (int c = 0; c < cols; c++) {
+				dt.Columns.Add ("Col" + c);
 			}
-				
-			for(int r = 0; r < rows; r++) {
-				var newRow = dt.NewRow();
 
-				for(int c = 0; c < cols; c++) {
-					newRow[c] = $"R{r}C{c}";
+			for (int r = 0; r < rows; r++) {
+				var newRow = dt.NewRow ();
+
+				for (int c = 0; c < cols; c++) {
+					newRow [c] = $"R{r}C{c}";
 				}
 
-				dt.Rows.Add(newRow);
+				dt.Rows.Add (newRow);
 			}
-			
+
 			return dt;
 		}
 	}

+ 51 - 8
UnitTests/TextFieldTests.cs

@@ -1,19 +1,38 @@
-using Xunit;
+using System;
+using System.Reflection;
+using Xunit;
 
 namespace Terminal.Gui.Views {
 	public class TextFieldTests {
-		private TextField _textField;
 
-		public TextFieldTests ()
-		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+		// This class enables test functions annoated with the [InitShutdown] attribute
+		// to have a function called before the test function is called and after.
+		// 
+		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
+		// as a pair, and b) all unit test functions should be atomic.
+		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+		public class InitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+
+			public override void Before (MethodInfo methodUnderTest)
+			{
+				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+				//                                     1         2         3 
+				//                           01234567890123456789012345678901=32 (Length)
+				TextFieldTests._textField = new TextField ("TAB to jump between text fields.");
+			}
 
-			//                                     1         2         3 
-			//                           01234567890123456789012345678901=32 (Length)
-			_textField = new TextField ("TAB to jump between text fields.");
+			public override void After (MethodInfo methodUnderTest)
+			{
+				TextFieldTests._textField = null;
+				Application.Shutdown ();
+			}
 		}
 
+		private static TextField _textField;
+
 		[Fact]
+		[InitShutdown]
 		public void Changing_SelectedStart_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		{
 			_textField.SelectedStart = 2;
@@ -27,6 +46,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void SelectedStart_With_Value_Less_Than_Minus_One_Changes_To_Minus_One ()
 		{
 			_textField.SelectedStart = -2;
@@ -36,6 +56,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void SelectedStart_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 			_textField.CursorPosition = 2;
@@ -46,6 +67,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void SelectedStart_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		{
 			_textField.CursorPosition = 33;
@@ -57,6 +79,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void SelectedStart_Greater_Than_CursorPosition_All_Selection_Is_Overwritten_On_Typing ()
 		{
 			_textField.SelectedStart = 19;
@@ -67,6 +90,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 			_textField.CursorPosition = -1;
@@ -76,6 +100,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 			_textField.CursorPosition = 33;
@@ -85,6 +110,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordForward_With_No_Selection ()
 		{
 			_textField.CursorPosition = 0;
@@ -135,6 +161,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordBackward_With_No_Selection ()
 		{
 			_textField.CursorPosition = _textField.Text.Length;
@@ -185,6 +212,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordForward_With_Selection ()
 		{
 			_textField.CursorPosition = 0;
@@ -236,6 +264,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordBackward_With_Selection ()
 		{
 			_textField.CursorPosition = _textField.Text.Length;
@@ -287,6 +316,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 			_textField.CursorPosition = 10;
@@ -326,6 +356,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 			_textField.CursorPosition = 10;
@@ -359,6 +390,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 			//                           1         2         3         4         5    
@@ -436,6 +468,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 			//                           1         2         3         4         5    
@@ -519,6 +552,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		{
 			_textField.SelectedStart = -1;
@@ -529,6 +563,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		{
 			_textField.SelectedStart = 20;
@@ -540,6 +575,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		{
 			_textField.SelectedStart = 20;
@@ -556,6 +592,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		{
 			_textField.SelectedStart = 20;
@@ -576,6 +613,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Copy_Or_Cut__Not_Allowed_If_Secret_Is_True ()
 		{
 			_textField.Secret = true;
@@ -593,6 +631,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Paste_Always_Clear_The_SelectedText ()
 		{
 			_textField.SelectedStart = 20;
@@ -604,6 +643,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void TextChanging_Event ()
 		{
 			bool cancel = true;
@@ -623,6 +663,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void TextChanged_Event ()
 		{
 			_textField.TextChanged += (e) => {
@@ -634,6 +675,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Used_Is_True_By_Default ()
 		{
 			_textField.CursorPosition = 10;
@@ -649,6 +691,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[InitShutdown]
 		public void Used_Is_False ()
 		{
 			_textField.Used = false;

+ 6 - 0
UnitTests/TextFormatterTests.cs

@@ -2533,6 +2533,9 @@ namespace Terminal.Gui.Core {
 				// After the fix this exception will not be caught.
 				Assert.IsType<IndexOutOfRangeException> (ex);
 			}
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -2561,6 +2564,9 @@ namespace Terminal.Gui.Core {
 				// After the fix this exception will not be caught.
 				Assert.IsType<IndexOutOfRangeException> (ex);
 			}
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 }

+ 46 - 7
UnitTests/TextValidateFieldTests.cs

@@ -1,16 +1,36 @@
-using System.Text.RegularExpressions;
+using System;
+using System.Reflection;
+using System.Text.RegularExpressions;
 using Terminal.Gui.TextValidateProviders;
 
 using Xunit;
 
 namespace Terminal.Gui.Views {
-	public class TextValidateField_NET_Provider_Tests {
-		public TextValidateField_NET_Provider_Tests ()
+
+	// This class enables test functions annoated with the [InitShutdown] attribute
+	// to have a function called before the test function is called and after.
+	// 
+	// This is necessary because a) Application is a singleton and Init/Shutdown must be called
+	// as a pair, and b) all unit test functions should be atomic.
+	[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+	public class TextValidateFieldInitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+
+		public override void Before (MethodInfo methodUnderTest)
 		{
 			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 		}
 
+		public override void After (MethodInfo methodUnderTest)
+		{
+			Application.Shutdown ();
+		}
+	}
+
+	public class TextValidateField_NET_Provider_Tests {
+
+
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Initialized_With_Cursor_On_First_Editable_Character ()
 		{
 			//                                                            *
@@ -27,6 +47,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Input_Ilegal_Character ()
 		{
 			//                                                            *
@@ -44,6 +65,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Home_Key_First_Editable_Character ()
 		{
 			//                                                            *
@@ -65,6 +87,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void End_Key_Last_Editable_Character ()
 		{
 			//                                                               *
@@ -84,6 +107,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Right_Key_Stops_In_Last_Editable_Character ()
 		{
 			//                                                               *
@@ -104,6 +128,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Left_Key_Stops_In_First_Editable_Character ()
 		{
 			//                                                            *
@@ -124,6 +149,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void When_Valid_Is_Valid_True ()
 		{
 			//                                                            ****
@@ -151,6 +177,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Insert_Skips_Non_Editable_Characters ()
 		{
 			//                                                            ** **
@@ -179,6 +206,7 @@ namespace Terminal.Gui.Views {
 
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Initial_Value_Exact_Valid ()
 		{
 			//                                                            ****
@@ -193,6 +221,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Initial_Value_Bigger_Than_Mask_Discarded ()
 		{
 			//                                                            ****
@@ -208,6 +237,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Initial_Value_Smaller_Than_Mask_Accepted ()
 		{
 			//                                                            ****
@@ -223,6 +253,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Delete_Key_Dosent_Move_Cursor ()
 		{
 			//                                                            ****
@@ -254,6 +285,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Backspace_Key_Deletes_Previous_Character ()
 		{
 			//                                                            ****
@@ -286,6 +318,7 @@ namespace Terminal.Gui.Views {
 
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Set_Text_After_Initialization ()
 		{
 			//                                                            ****
@@ -302,6 +335,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Changing_The_Mask_Tries_To_Keep_The_Previous_Text ()
 		{
 			//                                                            ****
@@ -322,6 +356,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void MouseClick_Right_X_Greater_Than_Text_Width_Goes_To_Last_Editable_Position ()
 		{
 			//                                                            ****
@@ -346,12 +381,9 @@ namespace Terminal.Gui.Views {
 	}
 
 	public class TextValidateField_Regex_Provider_Tests {
-		public TextValidateField_Regex_Provider_Tests ()
-		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Input_Without_Validate_On_Input ()
 		{
 			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
@@ -376,6 +408,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Input_With_Validate_On_Input_Set_Text ()
 		{
 			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
@@ -399,6 +432,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Text_With_All_Charset ()
 		{
 			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
@@ -416,6 +450,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Mask_With_Invalid_Pattern_Exception ()
 		{
 			// Regex Exception
@@ -438,6 +473,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Home_Key_First_Editable_Character ()
 		{
 			// Range 0 to 1000
@@ -465,6 +501,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void End_Key_End_Of_Input ()
 		{
 			// Exactly 5 numbers
@@ -499,6 +536,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Right_Key_Stops_At_End_And_Insert ()
 		{
 			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
@@ -523,6 +561,7 @@ namespace Terminal.Gui.Views {
 		}
 
 		[Fact]
+		[TextValidateFieldInitShutdown]
 		public void Left_Key_Stops_At_Start_And_Insert ()
 		{
 			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {

+ 77 - 57
UnitTests/TextViewTests.cs

@@ -1,28 +1,48 @@
 using System;
 using System.Linq;
+using System.Reflection;
 using Xunit;
 
 namespace Terminal.Gui.Views {
 	public class TextViewTests {
-		private TextView _textView;
+		private static TextView _textView;
+
+		// This class enables test functions annoated with the [InitShutdown] attribute
+		// to have a function called before the test function is called and after.
+		// 
+		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
+		// as a pair, and b) all unit test functions should be atomic.
+		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+		public class InitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+
+			public override void Before (MethodInfo methodUnderTest)
+			{
+				if (_textView != null) {
+					throw new InvalidOperationException ("After did not run.");
+				}
 
-		public TextViewTests ()
-		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-
-			//                   1         2         3 
-			//         01234567890123456789012345678901=32 (Length)
-			var txt = "TAB to jump between text fields.";
-			var buff = new byte [txt.Length];
-			for (int i = 0; i < txt.Length; i++) {
-				buff [i] = (byte)txt [i];
+				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+				//                   1         2         3 
+				//         01234567890123456789012345678901=32 (Length)
+				var txt = "TAB to jump between text fields.";
+				var buff = new byte [txt.Length];
+				for (int i = 0; i < txt.Length; i++) {
+					buff [i] = (byte)txt [i];
+				}
+				var ms = new System.IO.MemoryStream (buff).ToArray ();
+				_textView = new TextView () { Width = 30, Height = 10 };
+				_textView.Text = ms;
+			}
+
+			public override void After (MethodInfo methodUnderTest)
+			{
+				_textView = null;
+				Application.Shutdown ();
 			}
-			var ms = new System.IO.MemoryStream (buff).ToArray ();
-			_textView = new TextView () { Width = 30, Height = 10 };
-			_textView.Text = ms;
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Changing_Selection_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		{
 			_textView.SelectionStartColumn = 2;
@@ -38,7 +58,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("B to jump between ", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Selection_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 			_textView.SelectionStartColumn = -2;
@@ -49,7 +69,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Selection_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 			_textView.CursorPosition = new Point (2, 0);
@@ -61,7 +81,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("B to jump between text fields.", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Selection_With_Empty_Text ()
 		{
 			_textView = new TextView ();
@@ -74,7 +94,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Selection_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		{
 			_textView.CursorPosition = new Point (33, 2);
@@ -88,7 +108,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 			_textView.CursorPosition = new Point (-1, -1);
@@ -98,7 +118,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 			_textView.CursorPosition = new Point (33, 1);
@@ -108,7 +128,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordForward_With_No_Selection ()
 		{
 			_textView.CursorPosition = new Point (0, 0);
@@ -170,7 +190,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordBackward_With_No_Selection ()
 		{
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
@@ -232,7 +252,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordForward_With_Selection ()
 		{
 			_textView.CursorPosition = new Point (0, 0);
@@ -296,7 +316,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordBackward_With_Selection ()
 		{
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
@@ -360,7 +380,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 			_textView.CursorPosition = new Point (10, 0);
@@ -408,7 +428,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 			_textView.CursorPosition = new Point (10, 0);
@@ -448,7 +468,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 			//                          1         2         3         4         5    
@@ -545,7 +565,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 			//                          1         2         3         4         5    
@@ -650,7 +670,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordBackward_Multiline_With_Selection ()
 		{
 			//		          4         3          2         1
@@ -764,7 +784,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void WordForward_Multiline_With_Selection ()
 		{
 			//			    1         2          3         4
@@ -877,7 +897,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ()
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -912,7 +932,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ()
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -948,7 +968,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_Delete_WordForward ()
 		{
 			_textView.Text = "This is the first line.";
@@ -991,7 +1011,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_Delete_WordBackward ()
 		{
 			_textView.Text = "This is the first line.";
@@ -1035,7 +1055,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_Delete_WordForward_Multiline ()
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -1114,7 +1134,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Kill_Delete_WordBackward_Multiline ()
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -1193,7 +1213,7 @@ namespace Terminal.Gui.Views {
 			}
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		{
 			_textView.SelectionStartColumn = 0;
@@ -1204,7 +1224,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		{
 			_textView.SelectionStartColumn = 20;
@@ -1216,7 +1236,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		{
 			_textView.SelectionStartColumn = 20;
@@ -1234,7 +1254,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("TAB to jump between text fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		{
 			_textView.SelectionStartColumn = 20;
@@ -1262,7 +1282,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("TAB to jump between texttext fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Cut_Not_Allowed_If_ReadOnly_Is_True ()
 		{
 			_textView.ReadOnly = true;
@@ -1282,7 +1302,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Paste_Always_Clear_The_SelectedText ()
 		{
 			_textView.SelectionStartColumn = 20;
@@ -1294,7 +1314,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("", _textView.SelectedText);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void TextChanged_Event ()
 		{
 			_textView.TextChanged += () => {
@@ -1308,7 +1328,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("changed", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Used_Is_True_By_Default ()
 		{
 			_textView.CursorPosition = new Point (10, 0);
@@ -1323,7 +1343,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("TAB to jumusedp between text fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Used_Is_False ()
 		{
 			_textView.Used = false;
@@ -1339,7 +1359,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("TAB to jumusedtween text fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Copy_Without_Selection ()
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.\n";
@@ -1357,7 +1377,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (new Point (3, 3), _textView.CursorPosition);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void TabWidth_Setting_To_Zero_Changes_AllowsTab_To_False_If_True ()
 		{
 			Assert.Equal (4, _textView.TabWidth);
@@ -1375,7 +1395,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("TAB to jump between text fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void AllowsTab_Setting_To_True_Changes_TabWidth_To_Default_If_It_Is_Zero ()
 		{
 			_textView.TabWidth = 0;
@@ -1390,7 +1410,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (_textView.Multiline);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void AllowsReturn_Setting_To_True_Changes_Multiline_To_True_If_It_Is_False ()
 		{
 			Assert.True (_textView.AllowsReturn);
@@ -1411,7 +1431,7 @@ namespace Terminal.Gui.Views {
 				"TAB to jump between text fields.", _textView.Text);
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Multiline_Setting_Changes_AllowsReturn_And_AllowsTab_And_Height ()
 		{
 			Assert.True (_textView.Multiline);
@@ -1438,7 +1458,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ("Dim.Absolute(10)", _textView.Height.ToString ());
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Tab_Test_Follow_By_BackTab ()
 		{
 			Application.Top.Add (_textView);
@@ -1473,7 +1493,7 @@ namespace Terminal.Gui.Views {
 			Application.Run ();
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void BackTab_Test_Follow_By_Tab ()
 		{
 			Application.Top.Add (_textView);
@@ -1515,7 +1535,7 @@ namespace Terminal.Gui.Views {
 			Application.Run ();
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight ()
 		{
 			Application.Top.Add (_textView);
@@ -1557,7 +1577,7 @@ namespace Terminal.Gui.Views {
 			Application.Run ();
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Tab_Test_Follow_By_BackTab_With_Text ()
 		{
 			Application.Top.Add (_textView);
@@ -1592,7 +1612,7 @@ namespace Terminal.Gui.Views {
 			Application.Run ();
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Tab_Test_Follow_By_Home_And_Then_Follow_By_End_And_Then_Follow_By_BackTab_With_Text ()
 		{
 			Application.Top.Add (_textView);
@@ -1649,7 +1669,7 @@ namespace Terminal.Gui.Views {
 			Application.Run ();
 		}
 
-		[Fact]
+		[Fact][InitShutdown]
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight_With_Text ()
 		{
 			Application.Top.Add (_textView);

+ 15 - 0
UnitTests/TreeViewTests.cs

@@ -117,6 +117,8 @@ namespace Terminal.Gui.Views {
 			tree.Collapse (f);
 			//-+Factory
 			Assert.Equal (9, tree.GetContentWidth (true));
+
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -155,6 +157,8 @@ namespace Terminal.Gui.Views {
 			tree.ScrollOffsetVertical = 5;
 			Assert.Equal (0, tree.GetContentWidth (true));
 			Assert.Equal (13, tree.GetContentWidth (false));
+
+			Application.Shutdown ();
 		}
 		/// <summary>
 		/// Tests that <see cref="TreeView.IsExpanded(object)"/> and <see cref="TreeView.Expand(object)"/> behaves correctly when an object cannot be expanded (because it has no children)
@@ -179,6 +183,8 @@ namespace Terminal.Gui.Views {
 			tree.Collapse (c);
 
 			Assert.False (tree.IsExpanded (c));
+
+			Application.Shutdown ();
 		}
 
 		/// <summary>
@@ -497,6 +503,8 @@ namespace Terminal.Gui.Views {
 
 			Assert.True (called);
 			Assert.Same (f, activated);
+
+			Application.Shutdown ();
 		}
 
 
@@ -567,6 +575,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (called);
 			Assert.Same (f, activated);
 
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -593,6 +602,8 @@ namespace Terminal.Gui.Views {
 			Assert.True (called);
 			Assert.Same (f, activated);
 			Assert.Same (f, tree.SelectedObject);
+
+			Application.Shutdown ();
 		}
 
 		[Fact]
@@ -622,6 +633,8 @@ namespace Terminal.Gui.Views {
 			Assert.False (called);
 			Assert.Null (activated);
 			Assert.Null (tree.SelectedObject);
+
+			Application.Shutdown ();
 		}
 
 
@@ -657,6 +670,8 @@ namespace Terminal.Gui.Views {
 			Assert.True (called);
 			Assert.Same (car1, activated);
 			Assert.Same (car1, tree.SelectedObject);
+
+			Application.Shutdown ();
 		}
 
 

+ 3 - 0
UnitTests/ViewTests.cs

@@ -1166,6 +1166,9 @@ namespace Terminal.Gui.Views {
 			};
 
 			Application.Run ();
+
+			// Shutdown must be called to safely clean up Application if Init has been called
+			Application.Shutdown ();
 		}
 	}
 }