Преглед изворни кода

Merge branch 'develop' into line-drawer

Thomas Nind пре 2 година
родитељ
комит
16a3c0b8ae
84 измењених фајлова са 2421 додато и 1619 уклоњено
  1. 2 1
      .github/workflows/dotnet-core.yml
  2. 0 1
      README.md
  3. 0 0
      Terminal.Gui UnitTests/ScenarioTests.cs
  4. 57 0
      Terminal.Gui UnitTests/UnitTests.csproj
  5. 96 166
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  6. 8 4
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
  7. 71 8
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  8. 5 11
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeMainLoop.cs
  9. 3 3
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  10. 27 11
      Terminal.Gui/Core/Application.cs
  11. 38 11
      Terminal.Gui/Core/Clipboard/Clipboard.cs
  12. 25 20
      Terminal.Gui/Core/Clipboard/ClipboardBase.cs
  13. 78 131
      Terminal.Gui/Core/ConsoleDriver.cs
  14. 2 1
      Terminal.Gui/Core/MainLoop.cs
  15. 6 6
      Terminal.Gui/Core/TextFormatter.cs
  16. 5 4
      Terminal.Gui/Core/Toplevel.cs
  17. 21 7
      Terminal.Gui/Core/View.cs
  18. 0 1
      Terminal.Gui/README.md
  19. 4 4
      Terminal.Gui/Terminal.Gui.csproj
  20. 8 5
      Terminal.Gui/Views/ListView.cs
  21. 68 5
      Terminal.Gui/Views/TableView.cs
  22. 1 0
      Terminal.Gui/Views/TextField.cs
  23. 9 0
      Terminal.Gui/Windows/FileDialog.cs
  24. 13 15
      UICatalog/Properties/launchSettings.json
  25. 1 1
      UICatalog/Scenarios/Editor.cs
  26. 7 6
      UICatalog/UICatalog.cs
  27. 2 1
      UICatalog/UICatalog.csproj
  28. 15 12
      UnitTests/Application/ApplicationTests.cs
  29. 46 63
      UnitTests/Application/MainLoopTests.cs
  30. 13 7
      UnitTests/Application/RunStateTests.cs
  31. 1 1
      UnitTests/Application/StackExtensionsTests.cs
  32. 1 1
      UnitTests/Application/SynchronizatonContextTests.cs
  33. 0 324
      UnitTests/ClipboardTests.cs
  34. 1 1
      UnitTests/Core/BorderTests.cs
  35. 1 6
      UnitTests/Core/ResponderTests.cs
  36. 5 5
      UnitTests/Drivers/AttributeTests.cs
  37. 288 0
      UnitTests/Drivers/ClipboardTests.cs
  38. 39 0
      UnitTests/Drivers/ColorTests.cs
  39. 72 280
      UnitTests/Drivers/ConsoleDriverTests.cs
  40. 1 1
      UnitTests/Drivers/KeyTests.cs
  41. 2 2
      UnitTests/Menus/ContextMenuTests.cs
  42. 2 2
      UnitTests/Menus/MenuTests.cs
  43. 52 13
      UnitTests/TestHelpers.cs
  44. 1 1
      UnitTests/Text/CollectionNavigatorTests.cs
  45. 65 36
      UnitTests/Text/TextFormatterTests.cs
  46. 45 34
      UnitTests/TopLevels/DialogTests.cs
  47. 22 40
      UnitTests/TopLevels/MdiTests.cs
  48. 3 2
      UnitTests/TopLevels/MessageBoxTests.cs
  49. 22 15
      UnitTests/TopLevels/ToplevelTests.cs
  50. 8 7
      UnitTests/TopLevels/WindowTests.cs
  51. 21 21
      UnitTests/TopLevels/WizardTests.cs
  52. 14 19
      UnitTests/Types/DimTests.cs
  53. 1 1
      UnitTests/Types/PointTests.cs
  54. 9 10
      UnitTests/Types/PosTests.cs
  55. 1 1
      UnitTests/Types/RectTests.cs
  56. 1 1
      UnitTests/Types/SizeTests.cs
  57. 566 0
      UnitTests/UICatalog/ScenarioTests.cs
  58. 4 1
      UnitTests/UnitTests.csproj
  59. 3 3
      UnitTests/Views/AllViewsTests.cs
  60. 1 1
      UnitTests/Views/AutocompleteTests.cs
  61. 1 1
      UnitTests/Views/ButtonTests.cs
  62. 1 1
      UnitTests/Views/CheckboxTests.cs
  63. 1 1
      UnitTests/Views/ColorPickerTests.cs
  64. 1 1
      UnitTests/Views/ComboBoxTests.cs
  65. 1 1
      UnitTests/Views/DateFieldTests.cs
  66. 1 1
      UnitTests/Views/FrameViewTests.cs
  67. 3 3
      UnitTests/Views/GraphViewTests.cs
  68. 1 1
      UnitTests/Views/HexViewTests.cs
  69. 1 1
      UnitTests/Views/LineViewTests.cs
  70. 64 2
      UnitTests/Views/ListViewTests.cs
  71. 1 1
      UnitTests/Views/PanelViewTests.cs
  72. 1 1
      UnitTests/Views/ProgressBarTests.cs
  73. 1 1
      UnitTests/Views/RadioGroupTests.cs
  74. 22 31
      UnitTests/Views/ScrollBarViewTests.cs
  75. 1 1
      UnitTests/Views/ScrollViewTests.cs
  76. 2 2
      UnitTests/Views/StatusBarTests.cs
  77. 2 2
      UnitTests/Views/TabViewTests.cs
  78. 118 1
      UnitTests/Views/TableViewTests.cs
  79. 157 130
      UnitTests/Views/TextFieldTests.cs
  80. 1 1
      UnitTests/Views/TextValidateFieldTests.cs
  81. 83 86
      UnitTests/Views/TextViewTests.cs
  82. 1 1
      UnitTests/Views/TimeFieldTests.cs
  83. 2 2
      UnitTests/Views/TreeViewTests.cs
  84. 71 12
      UnitTests/Views/ViewTests.cs

+ 2 - 1
.github/workflows/dotnet-core.yml

@@ -20,7 +20,8 @@ jobs:
         dotnet-version: 6.0.100
         dotnet-version: 6.0.100
 
 
     - name: Install dependencies
     - name: Install dependencies
-      run: dotnet restore
+      run: |
+        dotnet restore
 
 
     - name: Build Debug
     - name: Build Debug
       run: dotnet build --configuration Debug --no-restore
       run: dotnet build --configuration Debug --no-restore

+ 0 - 1
README.md

@@ -12,7 +12,6 @@ A toolkit for building rich console apps for .NET, .NET Core, and Mono that work
 
 
 ![Sample app](docfx/images/sample.gif)
 ![Sample app](docfx/images/sample.gif)
 
 
-
 ## Quick Start
 ## Quick Start
 
 
 Paste these commands into your favorite terminal on Windows, Mac, or Linux. This will install the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates), create a new "Hello World" TUI app, and run it.
 Paste these commands into your favorite terminal on Windows, Mac, or Linux. This will install the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates), create a new "Hello World" TUI app, and run it.

+ 0 - 0
UnitTests/ScenarioTests.cs → Terminal.Gui UnitTests/ScenarioTests.cs


+ 57 - 0
Terminal.Gui UnitTests/UnitTests.csproj

@@ -0,0 +1,57 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <IsPackable>false</IsPackable>
+    <UseDataCollector />
+    <!-- Version numbers are automatically updated by gitversion when a release is released -->
+    <!-- In the source tree the version will always be 1.0 for all projects. -->
+    <!-- Do not modify these. -->
+    <AssemblyVersion>1.0</AssemblyVersion>
+    <FileVersion>1.0</FileVersion>
+    <Version>1.0</Version>
+    <InformationalVersion>1.0</InformationalVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+    <DefineConstants>TRACE</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
+    <PackageReference Include="ReportGenerator" Version="5.1.10" />
+    <PackageReference Include="System.Collections" Version="4.3.0" />
+    <PackageReference Include="xunit" Version="2.4.2" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="coverlet.collector" Version="3.2.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
+    <ProjectReference Include="..\UICatalog\UICatalog.csproj" />
+  </ItemGroup>
+  <PropertyGroup Label="FineCodeCoverage">
+    <Enabled>
+      True
+    </Enabled>
+    <Exclude>
+      [UICatalog]*
+    </Exclude>
+    <Include></Include>
+    <ExcludeByFile>
+      <!--**/Migrations/*
+      **/Hacks/*.cs-->
+    </ExcludeByFile>
+    <ExcludeByAttribute>
+      <!--MyCustomExcludeFromCodeCoverage-->
+    </ExcludeByAttribute>
+    <IncludeTestAssembly>
+      False
+    </IncludeTestAssembly>
+  </PropertyGroup>
+</Project>

+ 96 - 166
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -6,6 +6,7 @@
 //
 //
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -954,11 +955,13 @@ namespace Terminal.Gui {
 
 
 		public static bool Is_WSL_Platform ()
 		public static bool Is_WSL_Platform ()
 		{
 		{
-			if (new CursesClipboard ().IsSupported) {
-				return false;
-			}
-			var result = BashRunner.Run ("uname -a", runCurses: false);
-			if (result.Contains ("microsoft") && result.Contains ("WSL")) {
+			// xclip does not work on WSL, so we need to use the Windows clipboard vis Powershell
+			//if (new CursesClipboard ().IsSupported) {
+			//	// If xclip is installed on Linux under WSL, this will return true.
+			//	return false;
+			//}
+			var (exitCode, result) = ClipboardProcessRunner.Bash ("uname -a", waitForOutput: true);
+			if (exitCode == 0 && result.Contains ("microsoft") && result.Contains ("WSL")) {
 				return true;
 				return true;
 			}
 			}
 			return false;
 			return false;
@@ -1259,134 +1262,79 @@ namespace Terminal.Gui {
 		}
 		}
 	}
 	}
 
 
+	/// <summary>
+	///  A clipboard implementation for Linux.
+	///  This implementation uses the xclip command to access the clipboard.
+	/// </summary>	
+	/// <remarks>
+	/// If xclip is not installed, this implementation will not work.
+	/// </remarks>
 	class CursesClipboard : ClipboardBase {
 	class CursesClipboard : ClipboardBase {
 		public CursesClipboard ()
 		public CursesClipboard ()
 		{
 		{
 			IsSupported = CheckSupport ();
 			IsSupported = CheckSupport ();
 		}
 		}
 
 
+		string xclipPath = string.Empty;
 		public override bool IsSupported { get; }
 		public override bool IsSupported { get; }
 
 
 		bool CheckSupport ()
 		bool CheckSupport ()
 		{
 		{
 			try {
 			try {
-				var result = BashRunner.Run ("which xclip", runCurses: false);
-				return result.FileExists ();
+				var (exitCode, result) = ClipboardProcessRunner.Bash ("which xclip", waitForOutput: true);
+				if (exitCode == 0 && result.FileExists ()) {
+					xclipPath = result;
+					return true;
+				}
 			} catch (Exception) {
 			} catch (Exception) {
 				// Permissions issue.
 				// Permissions issue.
-				return false;
 			}
 			}
+			return false;
 		}
 		}
 
 
 		protected override string GetClipboardDataImpl ()
 		protected override string GetClipboardDataImpl ()
 		{
 		{
 			var tempFileName = System.IO.Path.GetTempFileName ();
 			var tempFileName = System.IO.Path.GetTempFileName ();
-			try {
-				// BashRunner.Run ($"xsel -o --clipboard > {tempFileName}");
-				BashRunner.Run ($"xclip -selection clipboard -o > {tempFileName}");
-				return System.IO.File.ReadAllText (tempFileName);
-			} finally {
-				System.IO.File.Delete (tempFileName);
-			}
-		}
-
-		protected override void SetClipboardDataImpl (string text)
-		{
-			// var tempFileName = System.IO.Path.GetTempFileName ();
-			// System.IO.File.WriteAllText (tempFileName, text);
-			// try {
-			// 	// BashRunner.Run ($"cat {tempFileName} | xsel -i --clipboard");
-			// 	BashRunner.Run ($"cat {tempFileName} | xclip -selection clipboard");
-			// } finally {
-			// 	System.IO.File.Delete (tempFileName);
-			// }
-
-			BashRunner.Run ("xclip -selection clipboard -i", false, text);
-		}
-	}
+			var xclipargs = "-selection clipboard -o";
 
 
-	static class BashRunner {
-		public static string Run (string commandLine, bool output = true, string inputText = "", bool runCurses = true)
-		{
-			var arguments = $"-c \"{commandLine}\"";
-
-			if (output) {
-				var errorBuilder = new System.Text.StringBuilder ();
-				var outputBuilder = new System.Text.StringBuilder ();
-
-				using (var process = new System.Diagnostics.Process {
-					StartInfo = new System.Diagnostics.ProcessStartInfo {
-						FileName = "bash",
-						Arguments = arguments,
-						RedirectStandardOutput = true,
-						RedirectStandardError = true,
-						UseShellExecute = false,
-						CreateNoWindow = false,
-					}
-				}) {
-					process.Start ();
-					process.OutputDataReceived += (sender, args) => { outputBuilder.AppendLine (args.Data); };
-					process.BeginOutputReadLine ();
-					process.ErrorDataReceived += (sender, args) => { errorBuilder.AppendLine (args.Data); };
-					process.BeginErrorReadLine ();
-					if (!process.DoubleWaitForExit ()) {
-						var timeoutError = $@"Process timed out. Command line: bash {arguments}.
-							Output: {outputBuilder}
-							Error: {errorBuilder}";
-						throw new Exception (timeoutError);
-					}
-					if (process.ExitCode == 0) {
-						if (runCurses && Application.Driver is CursesDriver) {
-							Curses.raw ();
-							Curses.noecho ();
-						}
-						return outputBuilder.ToString ();
-					}
-
-					var error = $@"Could not execute process. Command line: bash {arguments}.
-						Output: {outputBuilder}
-						Error: {errorBuilder}";
-					throw new Exception (error);
-				}
-			} else {
-				using (var process = new System.Diagnostics.Process {
-					StartInfo = new System.Diagnostics.ProcessStartInfo {
-						FileName = "bash",
-						Arguments = arguments,
-						RedirectStandardInput = true,
-						RedirectStandardError = true,
-						UseShellExecute = false,
-						CreateNoWindow = false
-					}
-				}) {
-					process.Start ();
-					process.StandardInput.Write (inputText);
-					process.StandardInput.Close ();
-					process.WaitForExit ();
-					if (runCurses && Application.Driver is CursesDriver) {
+			try {
+				var (exitCode, result) = ClipboardProcessRunner.Bash ($"{xclipPath} {xclipargs} > {tempFileName}", waitForOutput: false);
+				if (exitCode == 0) {
+					if (Application.Driver is CursesDriver) {
 						Curses.raw ();
 						Curses.raw ();
 						Curses.noecho ();
 						Curses.noecho ();
 					}
 					}
-					return inputText;
+					return System.IO.File.ReadAllText (tempFileName);
 				}
 				}
+			} catch (Exception e) {
+				throw new NotSupportedException ($"\"{xclipPath} {xclipargs}\" failed.", e);
+			} finally {
+				System.IO.File.Delete (tempFileName);
 			}
 			}
+			return string.Empty;
 		}
 		}
 
 
-		public static bool DoubleWaitForExit (this System.Diagnostics.Process process)
+		protected override void SetClipboardDataImpl (string text)
 		{
 		{
-			var result = process.WaitForExit (500);
-			if (result) {
-				process.WaitForExit ();
+			var xclipargs = "-selection clipboard -i";
+			try {
+				var (exitCode, _) = ClipboardProcessRunner.Bash ($"{xclipPath} {xclipargs}", text, waitForOutput: false);
+				if (exitCode == 0 && Application.Driver is CursesDriver) {
+					Curses.raw ();
+					Curses.noecho ();
+				}
+			} catch (Exception e) {
+				throw new NotSupportedException ($"\"{xclipPath} {xclipargs} < {text}\" failed", e);
 			}
 			}
-			return result;
-		}
-
-		public static bool FileExists (this string value)
-		{
-			return !string.IsNullOrEmpty (value) && !value.Contains ("not found");
 		}
 		}
 	}
 	}
 
 
+	/// <summary>
+	///  A clipboard implementation for MacOSX. 
+	///  This implementation uses the Mac clipboard API (via P/Invoke) to copy/paste.
+	///  The existance of the Mac pbcopy and pbpaste commands 
+	///  is used to determine if copy/paste is supported.
+	/// </summary>	
 	class MacOSXClipboard : ClipboardBase {
 	class MacOSXClipboard : ClipboardBase {
 		IntPtr nsString = objc_getClass ("NSString");
 		IntPtr nsString = objc_getClass ("NSString");
 		IntPtr nsPasteboard = objc_getClass ("NSPasteboard");
 		IntPtr nsPasteboard = objc_getClass ("NSPasteboard");
@@ -1413,12 +1361,12 @@ namespace Terminal.Gui {
 
 
 		bool CheckSupport ()
 		bool CheckSupport ()
 		{
 		{
-			var result = BashRunner.Run ("which pbcopy");
-			if (!result.FileExists ()) {
+			var (exitCode, result) = ClipboardProcessRunner.Bash ("which pbcopy", waitForOutput: true);
+			if (exitCode != 0 || !result.FileExists ()) {
 				return false;
 				return false;
 			}
 			}
-			result = BashRunner.Run ("which pbpaste");
-			return result.FileExists ();
+			(exitCode, result) = ClipboardProcessRunner.Bash ("which pbpaste", waitForOutput: true);
+			return exitCode == 0 && result.FileExists ();
 		}
 		}
 
 
 		protected override string GetClipboardDataImpl ()
 		protected override string GetClipboardDataImpl ()
@@ -1461,95 +1409,77 @@ namespace Terminal.Gui {
 		static extern IntPtr sel_registerName (string selectorName);
 		static extern IntPtr sel_registerName (string selectorName);
 	}
 	}
 
 
+	/// <summary>
+	///  A clipboard implementation for Linux, when running under WSL. 
+	///  This implementation uses the Windows clipboard to store the data, and uses Windows'
+	///  powershell.exe (launched via WSL interop services) to set/get the Windows
+	///  clipboard. 
+	/// </summary>
 	class WSLClipboard : ClipboardBase {
 	class WSLClipboard : ClipboardBase {
+		bool isSupported = false;
 		public WSLClipboard ()
 		public WSLClipboard ()
 		{
 		{
-			IsSupported = CheckSupport ();
+			isSupported = CheckSupport ();
 		}
 		}
 
 
-		public override bool IsSupported { get; }
+		public override bool IsSupported {
+			get {
+				return isSupported = CheckSupport ();
+			}
+		}
+
+		private static string powershellPath = string.Empty;
 
 
 		bool CheckSupport ()
 		bool CheckSupport ()
 		{
 		{
-			try {
-				var result = BashRunner.Run ("which powershell.exe");
-				return result.FileExists ();
-			} catch (System.Exception) {
-				return false;
-			}
+			if (string.IsNullOrEmpty (powershellPath)) {
+				// Specify pwsh.exe (not pwsh) to ensure we get the Windows version (invoked via WSL)
+				var (exitCode, result) = ClipboardProcessRunner.Bash ("which pwsh.exe", waitForOutput: true);
+				if (exitCode > 0) {
+					(exitCode, result) = ClipboardProcessRunner.Bash ("which powershell.exe", waitForOutput: true);
+				}
 
 
-			//var result = BashRunner.Run ("which powershell.exe");
-			//if (!result.FileExists ()) {
-			//	return false;
-			//}
-			//result = BashRunner.Run ("which clip.exe");
-			//return result.FileExists ();
+				if (exitCode == 0) {
+					powershellPath = result;
+				}
+			}
+			return !string.IsNullOrEmpty (powershellPath);
 		}
 		}
 
 
 		protected override string GetClipboardDataImpl ()
 		protected override string GetClipboardDataImpl ()
 		{
 		{
-			using (var powershell = new System.Diagnostics.Process {
-				StartInfo = new System.Diagnostics.ProcessStartInfo {
-					RedirectStandardOutput = true,
-					FileName = "powershell.exe",
-					Arguments = "-noprofile -command \"Get-Clipboard\"",
-					UseShellExecute = false,
-					CreateNoWindow = true
-				}
-			}) {
-				powershell.Start ();
-				var result = powershell.StandardOutput.ReadToEnd ();
-				powershell.StandardOutput.Close ();
-				if (!powershell.DoubleWaitForExit ()) {
-					var timeoutError = $@"Process timed out. Command line: bash {powershell.StartInfo.Arguments}.
-							Output: {powershell.StandardOutput.ReadToEnd ()}
-							Error: {powershell.StandardError.ReadToEnd ()}";
-					throw new Exception (timeoutError);
-				}
+			if (!IsSupported) {
+				return string.Empty;
+			}
+
+			var (exitCode, output) = ClipboardProcessRunner.Process (powershellPath, "-noprofile -command \"Get-Clipboard\"");
+			if (exitCode == 0) {
 				if (Application.Driver is CursesDriver) {
 				if (Application.Driver is CursesDriver) {
 					Curses.raw ();
 					Curses.raw ();
 					Curses.noecho ();
 					Curses.noecho ();
 				}
 				}
-				if (result.EndsWith ("\r\n")) {
-					result = result.Substring (0, result.Length - 2);
+
+				if (output.EndsWith ("\r\n")) {
+					output = output.Substring (0, output.Length - 2);
 				}
 				}
-				return result;
+				return output;
 			}
 			}
+			return string.Empty;
 		}
 		}
 
 
 		protected override void SetClipboardDataImpl (string text)
 		protected override void SetClipboardDataImpl (string text)
 		{
 		{
-			using (var powershell = new System.Diagnostics.Process {
-				StartInfo = new System.Diagnostics.ProcessStartInfo {
-					FileName = "powershell.exe",
-					Arguments = $"-noprofile -command \"Set-Clipboard -Value \\\"{text}\\\"\""
-				}
-			}) {
-				powershell.Start ();
-				powershell.WaitForExit ();
-				if (!powershell.DoubleWaitForExit ()) {
-					var timeoutError = $@"Process timed out. Command line: bash {powershell.StartInfo.Arguments}.
-							Output: {powershell.StandardOutput.ReadToEnd ()}
-							Error: {powershell.StandardError.ReadToEnd ()}";
-					throw new Exception (timeoutError);
-				}
+			if (!IsSupported) {
+				return;
+			}
+
+			var (exitCode, output) = ClipboardProcessRunner.Process (powershellPath, $"-noprofile -command \"Set-Clipboard -Value \\\"{text}\\\"\"");
+			if (exitCode == 0) {
 				if (Application.Driver is CursesDriver) {
 				if (Application.Driver is CursesDriver) {
 					Curses.raw ();
 					Curses.raw ();
 					Curses.noecho ();
 					Curses.noecho ();
 				}
 				}
 			}
 			}
-
-			//using (var clipExe = new System.Diagnostics.Process {
-			//	StartInfo = new System.Diagnostics.ProcessStartInfo {
-			//		FileName = "clip.exe",
-			//		RedirectStandardInput = true
-			//	}
-			//}) {
-			//	clipExe.Start ();
-			//	clipExe.StandardInput.Write (text);
-			//	clipExe.StandardInput.Close ();
-			//	clipExe.WaitForExit ();
-			//}
 		}
 		}
 	}
 	}
 }
 }

+ 8 - 4
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -38,6 +38,11 @@ namespace Terminal.Gui {
 	/// can watch file descriptors using the AddWatch methods.
 	/// can watch file descriptors using the AddWatch methods.
 	/// </remarks>
 	/// </remarks>
 	internal class UnixMainLoop : IMainLoopDriver {
 	internal class UnixMainLoop : IMainLoopDriver {
+		public UnixMainLoop (ConsoleDriver consoleDriver = null)
+		{
+			// UnixDriver doesn't use the consoleDriver parameter, but the WindowsDriver does.
+		}
+
 		public const int KEY_RESIZE = unchecked((int)0xffffffffffffffff);
 		public const int KEY_RESIZE = unchecked((int)0xffffffffffffffff);
 
 
 		[StructLayout (LayoutKind.Sequential)]
 		[StructLayout (LayoutKind.Sequential)]
@@ -176,16 +181,15 @@ namespace Terminal.Gui {
 		{
 		{
 			UpdatePollMap ();
 			UpdatePollMap ();
 
 
-			if (CheckTimers (wait, out var pollTimeout)) {
-				return true;
-			}
+			bool checkTimersResult = CheckTimers (wait, out var pollTimeout);
 
 
 			var n = poll (pollmap, (uint)pollmap.Length, pollTimeout);
 			var n = poll (pollmap, (uint)pollmap.Length, pollTimeout);
 
 
 			if (n == KEY_RESIZE) {
 			if (n == KEY_RESIZE) {
 				winChanged = true;
 				winChanged = true;
 			}
 			}
-			return n >= KEY_RESIZE || CheckTimers (wait, out pollTimeout);
+
+			return checkTimersResult || n >= KEY_RESIZE;
 		}
 		}
 
 
 		bool CheckTimers (bool wait, out int pollTimeout)
 		bool CheckTimers (bool wait, out int pollTimeout)

+ 71 - 8
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -6,10 +6,12 @@
 //
 //
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using NStack;
 using NStack;
+
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
@@ -19,6 +21,27 @@ namespace Terminal.Gui {
 	/// </summary>
 	/// </summary>
 	public class FakeDriver : ConsoleDriver {
 	public class FakeDriver : ConsoleDriver {
 #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
 #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
+
+		public class Behaviors {
+
+			public bool UseFakeClipboard { get; internal set; }
+			public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; }
+			public bool FakeClipboardIsSupportedAlwaysFalse { get; internal set; }
+
+			public Behaviors (bool useFakeClipboard = false, bool fakeClipboardAlwaysThrowsNotSupportedException = false, bool fakeClipboardIsSupportedAlwaysTrue = false)
+			{
+				UseFakeClipboard = useFakeClipboard;
+				FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException;
+				FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue;
+				
+				// double check usage is correct
+				Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false);
+				Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false);
+			}
+		}
+
+		public static FakeDriver.Behaviors FakeBehaviors = new Behaviors ();
+
 		int cols, rows, left, top;
 		int cols, rows, left, top;
 		public override int Cols => cols;
 		public override int Cols => cols;
 		public override int Rows => rows;
 		public override int Rows => rows;
@@ -26,7 +49,8 @@ namespace Terminal.Gui {
 		public override int Left => 0;
 		public override int Left => 0;
 		public override int Top => 0;
 		public override int Top => 0;
 		public override bool HeightAsBuffer { get; set; }
 		public override bool HeightAsBuffer { get; set; }
-		public override IClipboard Clipboard { get; }
+		private IClipboard clipboard = null;
+		public override IClipboard Clipboard => clipboard;
 
 
 		// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
 		// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
 		int [,,] contents;
 		int [,,] contents;
@@ -59,15 +83,19 @@ namespace Terminal.Gui {
 
 
 		public FakeDriver ()
 		public FakeDriver ()
 		{
 		{
-			if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
-				Clipboard = new WindowsClipboard ();
-			} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
-				Clipboard = new MacOSXClipboard ();
+			if (FakeBehaviors.UseFakeClipboard) {
+				clipboard = new FakeClipboard (FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException, FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse);
 			} else {
 			} else {
-				if (CursesDriver.Is_WSL_Platform ()) {
-					Clipboard = new WSLClipboard ();
+				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+					clipboard = new WindowsClipboard ();
+				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
+					clipboard = new MacOSXClipboard ();
 				} else {
 				} else {
-					Clipboard = new CursesClipboard ();
+					if (CursesDriver.Is_WSL_Platform ()) {
+						clipboard = new WSLClipboard ();
+					} else {
+						clipboard = new CursesClipboard ();
+					}
 				}
 				}
 			}
 			}
 		}
 		}
@@ -646,6 +674,41 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		#endregion
 		#endregion
+
+		public class FakeClipboard : ClipboardBase {
+			public Exception FakeException = null;
+
+			string contents = string.Empty;
+
+			bool isSupportedAlwaysFalse = false;
+
+			public override bool IsSupported => !isSupportedAlwaysFalse;
+
+			public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false, bool isSupportedAlwaysFalse = false)
+			{
+				this.isSupportedAlwaysFalse = isSupportedAlwaysFalse;
+				if (fakeClipboardThrowsNotSupportedException) {
+					FakeException = new NotSupportedException ("Fake clipboard exception");
+				}
+			}
+
+			protected override string GetClipboardDataImpl ()
+			{
+				if (FakeException != null) {
+					throw FakeException;
+				}
+				return contents;
+			}
+
+			protected override void SetClipboardDataImpl (string text)
+			{
+				if (FakeException != null) {
+					throw FakeException;
+				}
+				contents = text;
+			}
+		}
+
 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
 	}
 	}
 }
 }

+ 5 - 11
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeMainLoop.cs

@@ -15,7 +15,7 @@ namespace Terminal.Gui {
 		AutoResetEvent waitForProbe = new AutoResetEvent (false);
 		AutoResetEvent waitForProbe = new AutoResetEvent (false);
 		ConsoleKeyInfo? keyResult = null;
 		ConsoleKeyInfo? keyResult = null;
 		MainLoop mainLoop;
 		MainLoop mainLoop;
-		Func<ConsoleKeyInfo> consoleKeyReaderFn = null;
+		Func<ConsoleKeyInfo> consoleKeyReaderFn = () => FakeConsole.ReadKey (true);
 
 
 		/// <summary>
 		/// <summary>
 		/// Invoked when a Key is pressed.
 		/// Invoked when a Key is pressed.
@@ -23,18 +23,12 @@ namespace Terminal.Gui {
 		public Action<ConsoleKeyInfo> KeyPressed;
 		public Action<ConsoleKeyInfo> KeyPressed;
 
 
 		/// <summary>
 		/// <summary>
-		/// Initializes the class.
+		/// Creates an instance of the FakeMainLoop. <paramref name="consoleDriver"/> is not used.
 		/// </summary>
 		/// </summary>
-		/// <remarks>
-		///   Passing a consoleKeyReaderfn is provided to support unit test scenarios.
-		/// </remarks>
-		/// <param name="consoleKeyReaderFn">The method to be called to get a key from the console.</param>
-		public FakeMainLoop (Func<ConsoleKeyInfo> consoleKeyReaderFn = null)
+		/// <param name="consoleDriver"></param>
+		public FakeMainLoop (ConsoleDriver consoleDriver = null)
 		{
 		{
-			if (consoleKeyReaderFn == null) {
-				throw new ArgumentNullException ("key reader function must be provided.");
-			}
-			this.consoleKeyReaderFn = consoleKeyReaderFn;
+			// consoleDriver is not needed/used in FakeConsole
 		}
 		}
 
 
 		void WindowsKeyReader ()
 		void WindowsKeyReader ()

+ 3 - 3
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -251,7 +251,7 @@ namespace Terminal.Gui {
 				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 			}
 			}
 			var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0));
 			var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0));
-			if (!SetConsoleWindowInfo (ScreenBuffer, true, ref winRect)) {
+			if (!SetConsoleWindowInfo (OutputHandle, true, ref winRect)) {
 				//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 				//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 				return new Size (cols, rows);
 				return new Size (cols, rows);
 			}
 			}
@@ -261,7 +261,7 @@ namespace Terminal.Gui {
 
 
 		void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
 		void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
 		{
 		{
-			if (ScreenBuffer != IntPtr.Zero && !SetConsoleScreenBufferInfoEx (OutputHandle, ref csbi)) {
+			if (ScreenBuffer != IntPtr.Zero && !SetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) {
 				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 			}
 			}
 		}
 		}
@@ -773,7 +773,7 @@ namespace Terminal.Gui {
 					w += 3;
 					w += 3;
 				}
 				}
 				var newSize = WinConsole.SetConsoleWindow (
 				var newSize = WinConsole.SetConsoleWindow (
-					(short)Math.Max (w, 16), (short)Math.Max (e.Height, 1));
+					(short)Math.Max (w, 16), (short)Math.Max (e.Height, 0));
 				left = 0;
 				left = 0;
 				top = 0;
 				top = 0;
 				cols = newSize.Width;
 				cols = newSize.Width;

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

@@ -375,14 +375,14 @@ namespace Terminal.Gui {
 				ResetState ();
 				ResetState ();
 			}
 			}
 
 
-			// FakeDriver (for UnitTests)
+			// For UnitTests
 			if (driver != null) {
 			if (driver != null) {
-				if (mainLoopDriver == null) {
-					throw new ArgumentNullException ("InternalInit mainLoopDriver cannot be null if driver is provided.");
-				}
-				if (!(driver is FakeDriver)) {
-					throw new InvalidOperationException ("InternalInit can only be called with FakeDriver.");
-				}
+				//if (mainLoopDriver == null) {
+				//	throw new ArgumentNullException ("InternalInit mainLoopDriver cannot be null if driver is provided.");
+				//}
+				//if (!(driver is FakeDriver)) {
+				//	throw new InvalidOperationException ("InternalInit can only be called with FakeDriver.");
+				//}
 				Driver = driver;
 				Driver = driver;
 			}
 			}
 
 
@@ -391,18 +391,34 @@ namespace Terminal.Gui {
 				if (ForceFakeConsole) {
 				if (ForceFakeConsole) {
 					// For Unit Testing only
 					// For Unit Testing only
 					Driver = new FakeDriver ();
 					Driver = new FakeDriver ();
-					mainLoopDriver = new FakeMainLoop (() => FakeConsole.ReadKey (true));
 				} else if (UseSystemConsole) {
 				} else if (UseSystemConsole) {
 					Driver = new NetDriver ();
 					Driver = new NetDriver ();
-					mainLoopDriver = new NetMainLoop (Driver);
 				} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
 				} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
 					Driver = new WindowsDriver ();
 					Driver = new WindowsDriver ();
-					mainLoopDriver = new WindowsMainLoop (Driver);
 				} else {
 				} else {
-					mainLoopDriver = new UnixMainLoop ();
 					Driver = new CursesDriver ();
 					Driver = new CursesDriver ();
 				}
 				}
+				if (Driver == null) {
+					throw new InvalidOperationException ("Init could not determine the ConsoleDriver to use.");
+				}
 			}
 			}
+
+			if (mainLoopDriver == null) {
+				// TODO: Move this logic into ConsoleDriver
+				if (Driver is FakeDriver) {
+					mainLoopDriver = new FakeMainLoop (Driver);
+				} else if (Driver is NetDriver) {
+					mainLoopDriver = new NetMainLoop (Driver);
+				} else if (Driver is WindowsDriver) {
+					mainLoopDriver = new WindowsMainLoop (Driver);
+				} else if (Driver is CursesDriver) {
+					mainLoopDriver = new UnixMainLoop (Driver);
+				}
+				if (mainLoopDriver == null) {
+					throw new InvalidOperationException ("Init could not determine the MainLoopDriver to use.");
+				}
+			}
+
 			MainLoop = new MainLoop (mainLoopDriver);
 			MainLoop = new MainLoop (mainLoopDriver);
 
 
 			try {
 			try {

+ 38 - 11
Terminal.Gui/Core/Clipboard/Clipboard.cs

@@ -3,13 +3,32 @@ using System;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
-	/// Provides cut, copy, and paste support for the clipboard with OS interaction.
+	/// Provides cut, copy, and paste support for the OS clipboard.
 	/// </summary>
 	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// On Windows, the <see cref="Clipboard"/> class uses the Windows Clipboard APIs via P/Invoke.
+	/// </para>
+	/// <para>
+	/// On Linux, when not running under Windows Subsystem for Linux (WSL),
+	/// the <see cref="Clipboard"/> class uses the xclip command line tool. If xclip is not installed,
+	/// the clipboard will not work.
+	/// </para>
+	/// <para>
+	/// On Linux, when running under Windows Subsystem for Linux (WSL),
+	/// the <see cref="Clipboard"/> class launches Windows' powershell.exe via WSL interop and uses the
+	/// "Set-Clipboard" and "Get-Clipboard" Powershell CmdLets. 
+	/// </para>
+	/// <para>
+	/// On the Mac, the <see cref="Clipboard"/> class uses the MacO OS X pbcopy and pbpaste command line tools
+	/// and the Mac clipboard APIs vai P/Invoke.
+	/// </para>
+	/// </remarks>
 	public static class Clipboard {
 	public static class Clipboard {
 		static ustring contents;
 		static ustring contents;
 
 
 		/// <summary>
 		/// <summary>
-		/// Get or sets the operation system clipboard, otherwise the contents field.
+		/// Gets (copies from) or sets (pastes to) the contents of the OS clipboard.
 		/// </summary>
 		/// </summary>
 		public static ustring Contents {
 		public static ustring Contents {
 			get {
 			get {
@@ -25,10 +44,15 @@ namespace Terminal.Gui {
 			}
 			}
 			set {
 			set {
 				try {
 				try {
-					if (IsSupported && value != null) {
+					if (IsSupported) {
+						if (value == null) {
+							value = string.Empty;
+						}
 						Application.Driver.Clipboard.SetClipboardData (value.ToString ());
 						Application.Driver.Clipboard.SetClipboardData (value.ToString ());
 					}
 					}
 					contents = value;
 					contents = value;
+				} catch (NotSupportedException e) {
+					throw e;
 				} catch (Exception) {
 				} catch (Exception) {
 					contents = value;
 					contents = value;
 				}
 				}
@@ -38,32 +62,35 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
 		/// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
 		/// </summary>
 		/// </summary>
+		/// <remarks>
+		/// </remarks>
 		public static bool IsSupported { get => Application.Driver.Clipboard.IsSupported; }
 		public static bool IsSupported { get => Application.Driver.Clipboard.IsSupported; }
 
 
 		/// <summary>
 		/// <summary>
-		/// Gets the operation system clipboard if possible.
+		/// Copies the contents of the OS clipboard to <paramref name="result"/> if possible.
 		/// </summary>
 		/// </summary>
-		/// <param name="result">Clipboard contents read</param>
-		/// <returns>true if it was possible to read the OS clipboard.</returns>
+		/// <param name="result">The contents of the OS clipboard if successful, <see cref="string.Empty"/> if not.</param>
+		/// <returns><see langword="true"/> the OS clipboard was retrieved, <see langword="false"/> otherwise.</returns>
 		public static bool TryGetClipboardData (out string result)
 		public static bool TryGetClipboardData (out string result)
 		{
 		{
-			if (Application.Driver.Clipboard.TryGetClipboardData (out result)) {
+			if (IsSupported && Application.Driver.Clipboard.TryGetClipboardData (out result)) {
 				if (contents != result) {
 				if (contents != result) {
 					contents = result;
 					contents = result;
 				}
 				}
 				return true;
 				return true;
 			}
 			}
+			result = string.Empty;
 			return false;
 			return false;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Sets the operation system clipboard if possible.
+		/// Pastes the <paramref name="text"/> to the OS clipboard if possible.
 		/// </summary>
 		/// </summary>
-		/// <param name="text"></param>
-		/// <returns>True if the clipboard content was set successfully.</returns>
+		/// <param name="text">The text to paste to the OS clipboard.</param>
+		/// <returns><see langword="true"/> the OS clipboard was set, <see langword="false"/> otherwise.</returns>
 		public static bool TrySetClipboardData (string text)
 		public static bool TrySetClipboardData (string text)
 		{
 		{
-			if (Application.Driver.Clipboard.TrySetClipboardData (text)) {
+			if (IsSupported && Application.Driver.Clipboard.TrySetClipboardData (text)) {
 				contents = text;
 				contents = text;
 				return true;
 				return true;
 			}
 			}

+ 25 - 20
Terminal.Gui/Core/Clipboard/ClipboardBase.cs

@@ -15,48 +15,52 @@ namespace Terminal.Gui {
 		public abstract bool IsSupported { get; }
 		public abstract bool IsSupported { get; }
 
 
 		/// <summary>
 		/// <summary>
-		/// Get the operation system clipboard.
+		/// Returns the contents of the OS clipboard if possible.
 		/// </summary>
 		/// </summary>
-		/// <exception cref="NotSupportedException">Thrown if it was not possible to read the clipboard contents</exception>
+		/// <returns>The contents of the OS clipboard if successful.</returns>
+		/// <exception cref="NotSupportedException">Thrown if it was not possible to copy from the OS clipboard.</exception>
 		public string GetClipboardData ()
 		public string GetClipboardData ()
 		{
 		{
 			try {
 			try {
 				return GetClipboardDataImpl ();
 				return GetClipboardDataImpl ();
-			} catch (Exception ex) {
-				throw new NotSupportedException ("Failed to read clipboard.", ex);
+			} catch (NotSupportedException ex) {
+				throw new NotSupportedException ("Failed to copy from the OS clipboard.", ex);
 			}
 			}
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Get the operation system clipboard.
+		/// Returns the contents of the OS clipboard if possible. Implemented by <see cref="ConsoleDriver"/>-specific subclasses.
 		/// </summary>
 		/// </summary>
+		/// <returns>The contents of the OS clipboard if successful.</returns>
+		/// <exception cref="NotSupportedException">Thrown if it was not possible to copy from the OS clipboard.</exception>
 		protected abstract string GetClipboardDataImpl ();
 		protected abstract string GetClipboardDataImpl ();
 
 
 		/// <summary>
 		/// <summary>
-		/// Sets the operation system clipboard.
+		/// Pastes the <paramref name="text"/> to the OS clipboard if possible.
 		/// </summary>
 		/// </summary>
-		/// <param name="text"></param>
-		/// <exception cref="NotSupportedException">Thrown if it was not possible to set the clipboard contents</exception>
+		/// <param name="text">The text to paste to the OS clipboard.</param>
+		/// <exception cref="NotSupportedException">Thrown if it was not possible to paste to the OS clipboard.</exception>
 		public void SetClipboardData (string text)
 		public void SetClipboardData (string text)
 		{
 		{
 			try {
 			try {
 				SetClipboardDataImpl (text);
 				SetClipboardDataImpl (text);
-			} catch (Exception ex) {
-				throw new NotSupportedException ("Failed to write to clipboard.", ex);
+			} catch (NotSupportedException ex) {
+				throw new NotSupportedException ("Failed to paste to the OS clipboard.", ex);
 			}
 			}
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Sets the operation system clipboard.
+		/// Pastes the <paramref name="text"/> to the OS clipboard if possible. Implemented by <see cref="ConsoleDriver"/>-specific subclasses.
 		/// </summary>
 		/// </summary>
-		/// <param name="text"></param>
+		/// <param name="text">The text to paste to the OS clipboard.</param>
+		/// <exception cref="NotSupportedException">Thrown if it was not possible to paste to the OS clipboard.</exception>
 		protected abstract void SetClipboardDataImpl (string text);
 		protected abstract void SetClipboardDataImpl (string text);
 
 
 		/// <summary>
 		/// <summary>
-		/// Gets the operation system clipboard if possible.
+		/// Copies the contents of the OS clipboard to <paramref name="result"/> if possible.
 		/// </summary>
 		/// </summary>
-		/// <param name="result">Clipboard contents read</param>
-		/// <returns>true if it was possible to read the OS clipboard.</returns>
+		/// <param name="result">The contents of the OS clipboard if successful, <see cref="string.Empty"/> if not.</param>
+		/// <returns><see langword="true"/> the OS clipboard was retrieved, <see langword="false"/> otherwise.</returns>
 		public bool TryGetClipboardData (out string result)
 		public bool TryGetClipboardData (out string result)
 		{
 		{
 			// Don't even try to read because environment is not set up.
 			// Don't even try to read because environment is not set up.
@@ -71,17 +75,18 @@ namespace Terminal.Gui {
 					result = GetClipboardDataImpl ();
 					result = GetClipboardDataImpl ();
 				}
 				}
 				return true;
 				return true;
-			} catch (Exception) {
+			} catch (NotSupportedException ex) {
+				System.Diagnostics.Debug.WriteLine ($"TryGetClipboardData: {ex.Message}");
 				result = null;
 				result = null;
 				return false;
 				return false;
 			}
 			}
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Sets the operation system clipboard if possible.
+		/// Pastes the <paramref name="text"/> to the OS clipboard if possible.
 		/// </summary>
 		/// </summary>
-		/// <param name="text"></param>
-		/// <returns>True if the clipboard content was set successfully</returns>
+		/// <param name="text">The text to paste to the OS clipboard.</param>
+		/// <returns><see langword="true"/> the OS clipboard was set, <see langword="false"/> otherwise.</returns>
 		public bool TrySetClipboardData (string text)
 		public bool TrySetClipboardData (string text)
 		{
 		{
 			// Don't even try to set because environment is not set up
 			// Don't even try to set because environment is not set up
@@ -92,7 +97,7 @@ namespace Terminal.Gui {
 			try {
 			try {
 				SetClipboardDataImpl (text);
 				SetClipboardDataImpl (text);
 				return true;
 				return true;
-			} catch (Exception ex) {
+			} catch (NotSupportedException ex) {
 				System.Diagnostics.Debug.WriteLine ($"TrySetClipboardData: {ex.Message}");
 				System.Diagnostics.Debug.WriteLine ($"TrySetClipboardData: {ex.Message}");
 				return false;
 				return false;
 			}
 			}

+ 78 - 131
Terminal.Gui/Core/ConsoleDriver.cs

@@ -8,8 +8,11 @@
 using NStack;
 using NStack;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Unix.Terminal;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
@@ -209,153 +212,27 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// The default color for text, when the view is not focused.
 		/// The default color for text, when the view is not focused.
 		/// </summary>
 		/// </summary>
-		public Attribute Normal { get { return _normal; } set { _normal = SetAttribute (value); } }
+		public Attribute Normal { get { return _normal; } set { _normal = value; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// The color for text when the view has the focus.
 		/// The color for text when the view has the focus.
 		/// </summary>
 		/// </summary>
-		public Attribute Focus { get { return _focus; } set { _focus = SetAttribute (value); } }
+		public Attribute Focus { get { return _focus; } set { _focus = value; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// The color for the hotkey when a view is not focused
 		/// The color for the hotkey when a view is not focused
 		/// </summary>
 		/// </summary>
-		public Attribute HotNormal { get { return _hotNormal; } set { _hotNormal = SetAttribute (value); } }
+		public Attribute HotNormal { get { return _hotNormal; } set { _hotNormal = value; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// The color for the hotkey when the view is focused.
 		/// The color for the hotkey when the view is focused.
 		/// </summary>
 		/// </summary>
-		public Attribute HotFocus { get { return _hotFocus; } set { _hotFocus = SetAttribute (value); } }
+		public Attribute HotFocus { get { return _hotFocus; } set { _hotFocus = value; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// The default color for text, when the view is disabled.
 		/// The default color for text, when the view is disabled.
 		/// </summary>
 		/// </summary>
-		public Attribute Disabled { get { return _disabled; } set { _disabled = SetAttribute (value); } }
-
-		bool preparingScheme = false;
-
-		Attribute SetAttribute (Attribute attribute, [CallerMemberName] string callerMemberName = null)
-		{
-			if (!Application._initialized && !preparingScheme)
-				return attribute;
-
-			if (preparingScheme)
-				return attribute;
-
-			preparingScheme = true;
-			switch (caller) {
-			case "TopLevel":
-				switch (callerMemberName) {
-				case "Normal":
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					break;
-				case "Focus":
-					HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
-					break;
-				case "HotNormal":
-					HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
-					break;
-				case "HotFocus":
-					HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
-					if (Focus.Foreground != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
-					break;
-				}
-				break;
-
-			case "Base":
-				switch (callerMemberName) {
-				case "Normal":
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					break;
-				case "Focus":
-					HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
-					break;
-				case "HotNormal":
-					HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
-					Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
-					break;
-				case "HotFocus":
-					HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
-					if (Focus.Foreground != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
-					break;
-				}
-				break;
-
-			case "Menu":
-				switch (callerMemberName) {
-				case "Normal":
-					if (Focus.Background != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (attribute.Foreground, Focus.Background);
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					Disabled = Application.Driver.MakeAttribute (Disabled.Foreground, attribute.Background);
-					break;
-				case "Focus":
-					Normal = Application.Driver.MakeAttribute (attribute.Foreground, Normal.Background);
-					HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
-					break;
-				case "HotNormal":
-					if (Focus.Background != attribute.Background)
-						HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
-					Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
-					Disabled = Application.Driver.MakeAttribute (Disabled.Foreground, attribute.Background);
-					break;
-				case "HotFocus":
-					HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
-					if (Focus.Foreground != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
-					break;
-				case "Disabled":
-					if (Focus.Background != attribute.Background)
-						HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
-					Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					break;
-				}
-				break;
-
-			case "Dialog":
-				switch (callerMemberName) {
-				case "Normal":
-					if (Focus.Background != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (attribute.Foreground, Focus.Background);
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					break;
-				case "Focus":
-					Normal = Application.Driver.MakeAttribute (attribute.Foreground, Normal.Background);
-					HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
-					break;
-				case "HotNormal":
-					if (Focus.Background != attribute.Background)
-						HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, HotFocus.Background);
-					if (Normal.Foreground != attribute.Background)
-						Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
-					break;
-				case "HotFocus":
-					HotNormal = Application.Driver.MakeAttribute (attribute.Foreground, HotNormal.Background);
-					if (Focus.Foreground != attribute.Background)
-						Focus = Application.Driver.MakeAttribute (Focus.Foreground, attribute.Background);
-					break;
-				}
-				break;
-
-			case "Error":
-				switch (callerMemberName) {
-				case "Normal":
-					HotNormal = Application.Driver.MakeAttribute (HotNormal.Foreground, attribute.Background);
-					HotFocus = Application.Driver.MakeAttribute (HotFocus.Foreground, attribute.Background);
-					break;
-				case "HotNormal":
-				case "HotFocus":
-					HotFocus = Application.Driver.MakeAttribute (attribute.Foreground, attribute.Background);
-					Normal = Application.Driver.MakeAttribute (Normal.Foreground, attribute.Background);
-					break;
-				}
-				break;
-			}
-			preparingScheme = false;
-			return attribute;
-		}
+		public Attribute Disabled { get { return _disabled; } set { _disabled = value; } }
 
 
 		/// <summary>
 		/// <summary>
 		/// Compares two <see cref="ColorScheme"/> objects for equality.
 		/// Compares two <see cref="ColorScheme"/> objects for equality.
@@ -1389,4 +1266,74 @@ namespace Terminal.Gui {
 			Colors.Error.Disabled = MakeColor (Color.DarkGray, Color.White);
 			Colors.Error.Disabled = MakeColor (Color.DarkGray, Color.White);
 		}
 		}
 	}
 	}
+
+	/// <summary>
+	/// Helper class for console drivers to invoke shell commands to interact with the clipboard.
+	/// Used primarily by CursesDriver, but also used in Unit tests which is why it is in
+	/// ConsoleDriver.cs.
+	/// </summary>
+	internal static class ClipboardProcessRunner {
+		public static (int exitCode, string result) Bash (string commandLine, string inputText = "", bool waitForOutput = false)
+		{
+			var arguments = $"-c \"{commandLine}\"";
+			var (exitCode, result) = Process ("bash", arguments, inputText, waitForOutput);
+
+			return (exitCode, result.TrimEnd ());
+		}
+
+		public static (int exitCode, string result) Process (string cmd, string arguments, string input = null, bool waitForOutput = true)
+		{
+			var output = string.Empty;
+
+			using (Process process = new Process {
+				StartInfo = new ProcessStartInfo {
+					FileName = cmd,
+					Arguments = arguments,
+					RedirectStandardOutput = true,
+					RedirectStandardError = true,
+					RedirectStandardInput = true,
+					UseShellExecute = false,
+					CreateNoWindow = true,
+				}
+			}) {
+				var eventHandled = new TaskCompletionSource<bool> ();
+				process.Start ();
+				if (!string.IsNullOrEmpty (input)) {
+					process.StandardInput.Write (input);
+					process.StandardInput.Close ();
+				}
+
+				if (!process.WaitForExit (5000)) {
+					var timeoutError = $@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
+					throw new TimeoutException (timeoutError);
+				}
+
+				if (waitForOutput && process.StandardOutput.Peek () != -1) {
+					output = process.StandardOutput.ReadToEnd ();
+				}
+
+				if (process.ExitCode > 0) {
+					output = $@"Process failed to run. Command line: {cmd} {arguments}.
+										Output: {output}
+										Error: {process.StandardError.ReadToEnd ()}";
+				}
+
+				return (process.ExitCode, output);
+			}
+		}
+
+		public static bool DoubleWaitForExit (this System.Diagnostics.Process process)
+		{
+			var result = process.WaitForExit (500);
+			if (result) {
+				process.WaitForExit ();
+			}
+			return result;
+		}
+
+		public static bool FileExists (this string value)
+		{
+			return !string.IsNullOrEmpty (value) && !value.Contains ("not found");
+		}
+	}
 }
 }

+ 2 - 1
Terminal.Gui/Core/MainLoop.cs

@@ -102,7 +102,8 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		///  Creates a new Mainloop. 
 		///  Creates a new Mainloop. 
 		/// </summary>
 		/// </summary>
-		/// <param name="driver">Should match the <see cref="ConsoleDriver"/> (one of the implementations UnixMainLoop, NetMainLoop or WindowsMainLoop).</param>
+		/// <param name="driver">Should match the <see cref="ConsoleDriver"/> 
+		/// (one of the implementations FakeMainLoop, UnixMainLoop, NetMainLoop or WindowsMainLoop).</param>
 		public MainLoop (IMainLoopDriver driver)
 		public MainLoop (IMainLoopDriver driver)
 		{
 		{
 			Driver = driver;
 			Driver = driver;

+ 6 - 6
Terminal.Gui/Core/TextFormatter.cs

@@ -1212,11 +1212,11 @@ namespace Terminal.Gui {
 					if (isVertical) {
 					if (isVertical) {
 						var runesWidth = GetSumMaxCharWidth (Lines, line);
 						var runesWidth = GetSumMaxCharWidth (Lines, line);
 						x = bounds.Right - runesWidth;
 						x = bounds.Right - runesWidth;
-						CursorPosition = bounds.Width - runesWidth + hotKeyPos;
+						CursorPosition = bounds.Width - runesWidth + (hotKeyPos > -1 ? hotKeyPos : 0);
 					} else {
 					} else {
 						var runesWidth = GetTextWidth (ustring.Make (runes));
 						var runesWidth = GetTextWidth (ustring.Make (runes));
 						x = bounds.Right - runesWidth;
 						x = bounds.Right - runesWidth;
-						CursorPosition = bounds.Width - runesWidth + hotKeyPos;
+						CursorPosition = bounds.Width - runesWidth + (hotKeyPos > -1 ? hotKeyPos : 0);
 					}
 					}
 				} else if (textAlignment == TextAlignment.Left || textAlignment == TextAlignment.Justified) {
 				} else if (textAlignment == TextAlignment.Left || textAlignment == TextAlignment.Justified) {
 					if (isVertical) {
 					if (isVertical) {
@@ -1225,16 +1225,16 @@ namespace Terminal.Gui {
 					} else {
 					} else {
 						x = bounds.Left;
 						x = bounds.Left;
 					}
 					}
-					CursorPosition = hotKeyPos;
+					CursorPosition = hotKeyPos > -1 ? hotKeyPos : 0;
 				} else if (textAlignment == TextAlignment.Centered) {
 				} else if (textAlignment == TextAlignment.Centered) {
 					if (isVertical) {
 					if (isVertical) {
 						var runesWidth = GetSumMaxCharWidth (Lines, line);
 						var runesWidth = GetSumMaxCharWidth (Lines, line);
 						x = bounds.Left + line + ((bounds.Width - runesWidth) / 2);
 						x = bounds.Left + line + ((bounds.Width - runesWidth) / 2);
-						CursorPosition = (bounds.Width - runesWidth) / 2 + hotKeyPos;
+						CursorPosition = (bounds.Width - runesWidth) / 2 + (hotKeyPos > -1 ? hotKeyPos : 0);
 					} else {
 					} else {
 						var runesWidth = GetTextWidth (ustring.Make (runes));
 						var runesWidth = GetTextWidth (ustring.Make (runes));
 						x = bounds.Left + (bounds.Width - runesWidth) / 2;
 						x = bounds.Left + (bounds.Width - runesWidth) / 2;
-						CursorPosition = (bounds.Width - runesWidth) / 2 + hotKeyPos;
+						CursorPosition = (bounds.Width - runesWidth) / 2 + (hotKeyPos > -1 ? hotKeyPos : 0);
 					}
 					}
 				} else {
 				} else {
 					throw new ArgumentOutOfRangeException ();
 					throw new ArgumentOutOfRangeException ();
@@ -1291,7 +1291,7 @@ namespace Terminal.Gui {
 							rune = runes [idx];
 							rune = runes [idx];
 						}
 						}
 					}
 					}
-					if (idx == HotKeyPos) {
+					if (HotKeyPos > -1 && idx == HotKeyPos) {
 						if ((isVertical && textVerticalAlignment == VerticalTextAlignment.Justified) ||
 						if ((isVertical && textVerticalAlignment == VerticalTextAlignment.Justified) ||
 						(!isVertical && textAlignment == TextAlignment.Justified)) {
 						(!isVertical && textAlignment == TextAlignment.Justified)) {
 							CursorPosition = idx - start;
 							CursorPosition = idx - start;

+ 5 - 4
Terminal.Gui/Core/Toplevel.cs

@@ -613,8 +613,9 @@ namespace Terminal.Gui {
 			}
 			}
 			nx = Math.Max (x, 0);
 			nx = Math.Max (x, 0);
 			nx = nx + top.Frame.Width > l ? Math.Max (l - top.Frame.Width, 0) : nx;
 			nx = nx + top.Frame.Width > l ? Math.Max (l - top.Frame.Width, 0) : nx;
-			if (nx + (top.Border != null && top.Border.DrawMarginFrame ? 2 : 1) > top.Frame.X + top.Frame.Width) {
-				nx = Math.Max (top.Frame.Right - (top.Border.DrawMarginFrame ? 2 : 1), 0);
+			var mfLength = top.Border?.DrawMarginFrame == true ? 2 : 1;
+			if (nx + mfLength > top.Frame.X + top.Frame.Width) {
+				nx = Math.Max (top.Frame.Right - mfLength, 0);
 			}
 			}
 			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
 			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
 			bool m, s;
 			bool m, s;
@@ -653,8 +654,8 @@ namespace Terminal.Gui {
 			}
 			}
 			ny = Math.Min (ny, l);
 			ny = Math.Min (ny, l);
 			ny = ny + top.Frame.Height >= l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
 			ny = ny + top.Frame.Height >= l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
-			if (ny + (top.Border != null && top.Border.DrawMarginFrame ? 2 : 1) > top.Frame.Y + top.Frame.Height) {
-				ny = Math.Max (top.Frame.Bottom - (top.Border.DrawMarginFrame ? 2 : 1), 0);
+			if (ny + mfLength > top.Frame.Y + top.Frame.Height) {
+				ny = Math.Max (top.Frame.Bottom - mfLength, 0);
 			}
 			}
 			//System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
 			//System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
 
 

+ 21 - 7
Terminal.Gui/Core/View.cs

@@ -1093,8 +1093,15 @@ namespace Terminal.Gui {
 		/// </remarks>
 		/// </remarks>
 		public void Clear ()
 		public void Clear ()
 		{
 		{
-			var h = Frame.Height;
-			var w = Frame.Width;
+			Rect containerBounds = GetContainerBounds ();
+			Rect viewBounds = Bounds;
+			if (!containerBounds.IsEmpty) {
+				viewBounds.Width = Math.Min (viewBounds.Width, containerBounds.Width);
+				viewBounds.Height = Math.Min (viewBounds.Height, containerBounds.Height);
+			}
+
+			var h = viewBounds.Height;
+			var w = viewBounds.Width;
 			for (var line = 0; line < h; line++) {
 			for (var line = 0; line < h; line++) {
 				Move (0, line);
 				Move (0, line);
 				for (var col = 0; col < w; col++)
 				for (var col = 0; col < w; col++)
@@ -1511,11 +1518,7 @@ namespace Terminal.Gui {
 				if (TextFormatter != null) {
 				if (TextFormatter != null) {
 					TextFormatter.NeedsFormat = true;
 					TextFormatter.NeedsFormat = true;
 				}
 				}
-				var containerBounds = SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds);
-				containerBounds.X = Math.Max (containerBounds.X, Driver.Clip.X);
-				containerBounds.Y = Math.Max (containerBounds.Y, Driver.Clip.Y);
-				containerBounds.Width = Math.Min (containerBounds.Width, Driver.Clip.Width);
-				containerBounds.Height = Math.Min (containerBounds.Height, Driver.Clip.Height);
+				Rect containerBounds = GetContainerBounds ();
 				TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
 				TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (),
 				    HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
 				    HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
 				    containerBounds);
 				    containerBounds);
@@ -1558,6 +1561,17 @@ namespace Terminal.Gui {
 			ClearNeedsDisplay ();
 			ClearNeedsDisplay ();
 		}
 		}
 
 
+		Rect GetContainerBounds ()
+		{
+			var containerBounds = SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds);
+			var driverClip = Driver == null ? Rect.Empty : Driver.Clip;
+			containerBounds.X = Math.Max (containerBounds.X, driverClip.X);
+			containerBounds.Y = Math.Max (containerBounds.Y, driverClip.Y);
+			containerBounds.Width = Math.Min (containerBounds.Width, driverClip.Width);
+			containerBounds.Height = Math.Min (containerBounds.Height, driverClip.Height);
+			return containerBounds;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Event invoked when the content area of the View is to be drawn.
 		/// Event invoked when the content area of the View is to be drawn.
 		/// </summary>
 		/// </summary>

+ 0 - 1
Terminal.Gui/README.md

@@ -68,7 +68,6 @@ The PR title should be of the form "Release v2.3.4"
 git checkout develop
 git checkout develop
 git pull upstream develop
 git pull upstream develop
 git checkout -b v_2_3_4
 git checkout -b v_2_3_4
-git merge develop
 git add .
 git add .
 git commit -m "Release v2.3.4"
 git commit -m "Release v2.3.4"
 git push
 git push

+ 4 - 4
Terminal.Gui/Terminal.Gui.csproj

@@ -10,12 +10,12 @@
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- Do not modify these. Do NOT commit after manually running `dotnet-gitversion /updateprojectfiles` -->
     <!-- Do not modify these. Do NOT commit after manually running `dotnet-gitversion /updateprojectfiles` -->
-    <AssemblyVersion>1.0</AssemblyVersion>
-    <FileVersion>1.0</FileVersion>
-    <Version>1.0</Version>
-    <InformationalVersion>1.0</InformationalVersion>
+    <AssemblyVersion>1.9</AssemblyVersion>
+    <Version>1.9</Version>
+    <InformationalVersion>1.9</InformationalVersion>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
+    <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
     <PackageReference Include="NStack.Core" Version="1.0.7" />
     <PackageReference Include="NStack.Core" Version="1.0.7" />
     <InternalsVisibleTo Include="UnitTests" />
     <InternalsVisibleTo Include="UnitTests" />

+ 8 - 5
Terminal.Gui/Views/ListView.cs

@@ -430,7 +430,7 @@ namespace Terminal.Gui {
 				var newItem = KeystrokeNavigator?.GetNextMatchingItem (SelectedItem, (char)kb.KeyValue);
 				var newItem = KeystrokeNavigator?.GetNextMatchingItem (SelectedItem, (char)kb.KeyValue);
 				if (newItem is int && newItem != -1) {
 				if (newItem is int && newItem != -1) {
 					SelectedItem = (int)newItem;
 					SelectedItem = (int)newItem;
-					EnsuresVisibilitySelectedItem ();
+					EnsureSelectedItemVisible ();
 					SetNeedsDisplay ();
 					SetNeedsDisplay ();
 					return true;
 					return true;
 				}
 				}
@@ -727,7 +727,7 @@ namespace Terminal.Gui {
 			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
 			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
 
 
 			if (lastSelectedItem == -1) {
 			if (lastSelectedItem == -1) {
-				EnsuresVisibilitySelectedItem ();
+				EnsureSelectedItemVisible ();
 			}
 			}
 
 
 			return base.OnEnter (view);
 			return base.OnEnter (view);
@@ -743,7 +743,10 @@ namespace Terminal.Gui {
 			return base.OnLeave (view);
 			return base.OnLeave (view);
 		}
 		}
 
 
-		void EnsuresVisibilitySelectedItem ()
+		/// <summary>
+		/// Ensures the selected item is always visible on the screen.
+		/// </summary>
+		public void EnsureSelectedItemVisible ()
 		{
 		{
 			SuperView?.LayoutSubviews ();
 			SuperView?.LayoutSubviews ();
 			if (selected < top) {
 			if (selected < top) {
@@ -840,7 +843,7 @@ namespace Terminal.Gui {
 			if (src == null || src?.Count == 0) {
 			if (src == null || src?.Count == 0) {
 				return 0;
 				return 0;
 			}
 			}
-			
+
 			int maxLength = 0;
 			int maxLength = 0;
 			for (int i = 0; i < src.Count; i++) {
 			for (int i = 0; i < src.Count; i++) {
 				var t = src [i];
 				var t = src [i];
@@ -924,7 +927,7 @@ namespace Terminal.Gui {
 						return i;
 						return i;
 					}
 					}
 				} else if (t is string s) {
 				} else if (t is string s) {
-					if (s.ToUpperInvariant ().StartsWith (search.ToUpperInvariant ())) {
+					if (s.StartsWith (search, StringComparison.InvariantCultureIgnoreCase)) {
 						return i;
 						return i;
 					}
 					}
 				}
 				}

+ 68 - 5
Terminal.Gui/Views/TableView.cs

@@ -761,6 +761,41 @@ namespace Terminal.Gui {
 			SelectedRow = row;
 			SelectedRow = row;
 		}
 		}
 
 
+		/// <summary>
+		/// Unions the current selected cell (and/or regions) with the provided cell and makes
+		/// it the active one.
+		/// </summary>
+		/// <param name="col"></param>
+		/// <param name="row"></param>
+		private void UnionSelection (int col, int row)
+		{
+			if (!MultiSelect || TableIsNullOrInvisible()) {
+				return;
+			}
+			
+			EnsureValidSelection ();
+
+			var oldColumn = SelectedColumn;
+			var oldRow = SelectedRow;
+
+			// move us to the new cell
+			SelectedColumn = col;
+			SelectedRow = row;
+			MultiSelectedRegions.Push (
+				CreateTableSelection (col, row)
+				);
+
+			// if the old cell was not part of a rectangular select
+			// or otherwise selected we need to retain it in the selection
+
+			if (!IsSelected (oldColumn, oldRow)) {
+				MultiSelectedRegions.Push (
+					CreateTableSelection (oldColumn, oldRow)
+					);
+			}
+		}
+
+
 		/// <summary>
 		/// <summary>
 		/// Moves the <see cref="SelectedRow"/> and <see cref="SelectedColumn"/> by the provided offsets. Optionally starting a box selection (see <see cref="MultiSelect"/>)
 		/// Moves the <see cref="SelectedRow"/> and <see cref="SelectedColumn"/> by the provided offsets. Optionally starting a box selection (see <see cref="MultiSelect"/>)
 		/// </summary>
 		/// </summary>
@@ -794,22 +829,28 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Moves or extends the selection to the first cell in the table (0,0)
+		/// Moves or extends the selection to the first cell in the table (0,0).
+		/// If <see cref="FullRowSelect"/> is enabled then selection instead moves
+		/// to (<see cref="SelectedColumn"/>,0) i.e. no horizontal scrolling.
 		/// </summary>
 		/// </summary>
 		/// <param name="extend">true to extend the current selection (if any) instead of replacing</param>
 		/// <param name="extend">true to extend the current selection (if any) instead of replacing</param>
 		public void ChangeSelectionToStartOfTable (bool extend)
 		public void ChangeSelectionToStartOfTable (bool extend)
 		{
 		{
-			SetSelection (0, 0, extend);
+			SetSelection (FullRowSelect ? SelectedColumn : 0, 0, extend);
 			Update ();
 			Update ();
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Moves or extends the selection to the final cell in the table
+		/// Moves or extends the selection to the final cell in the table (nX,nY).
+		/// If <see cref="FullRowSelect"/> is enabled then selection instead moves
+		/// to (<see cref="SelectedColumn"/>,nY) i.e. no horizontal scrolling.
 		/// </summary>
 		/// </summary>
 		/// <param name="extend">true to extend the current selection (if any) instead of replacing</param>
 		/// <param name="extend">true to extend the current selection (if any) instead of replacing</param>
 		public void ChangeSelectionToEndOfTable(bool extend)
 		public void ChangeSelectionToEndOfTable(bool extend)
 		{
 		{
-			SetSelection (Table.Columns.Count - 1, Table.Rows.Count - 1, extend);
+			var finalColumn = Table.Columns.Count - 1;
+
+			SetSelection (FullRowSelect ? SelectedColumn : finalColumn, Table.Rows.Count - 1, extend);
 			Update ();
 			Update ();
 		}
 		}
 
 
@@ -852,6 +893,8 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Returns all cells in any <see cref="MultiSelectedRegions"/> (if <see cref="MultiSelect"/> is enabled) and the selected cell
 		/// Returns all cells in any <see cref="MultiSelectedRegions"/> (if <see cref="MultiSelect"/> is enabled) and the selected cell
 		/// </summary>
 		/// </summary>
+		/// <remarks>Return value is not affected by <see cref="FullRowSelect"/> (i.e. returned <see cref="Point"/>s are not expanded to 
+		/// include all points on row).</remarks>
 		/// <returns></returns>
 		/// <returns></returns>
 		public IEnumerable<Point> GetAllSelectedCells ()
 		public IEnumerable<Point> GetAllSelectedCells ()
 		{
 		{
@@ -914,6 +957,16 @@ namespace Terminal.Gui {
 			return new TableSelection (new Point (pt1X, pt1Y), new Rect (left, top, right - left + 1, bot - top + 1));
 			return new TableSelection (new Point (pt1X, pt1Y), new Rect (left, top, right - left + 1, bot - top + 1));
 		}
 		}
 
 
+		/// <summary>
+		/// Returns a single point as a <see cref="TableSelection"/>
+		/// </summary>
+		/// <param name="x"></param>
+		/// <param name="y"></param>
+		/// <returns></returns>
+		private TableSelection CreateTableSelection (int x, int y)
+		{
+			return CreateTableSelection (x, y, x, y);
+		}
 		/// <summary>
 		/// <summary>
 		/// <para>
 		/// <para>
 		/// Returns true if the given cell is selected either because it is the active cell or part of a multi cell selection (e.g. <see cref="FullRowSelect"/>).
 		/// Returns true if the given cell is selected either because it is the active cell or part of a multi cell selection (e.g. <see cref="FullRowSelect"/>).
@@ -1039,7 +1092,12 @@ namespace Terminal.Gui {
 				var hit = ScreenToCell (me.X, me.Y);
 				var hit = ScreenToCell (me.X, me.Y);
 				if (hit != null) {
 				if (hit != null) {
 
 
-					SetSelection (hit.Value.X, hit.Value.Y, me.Flags.HasFlag (MouseFlags.ButtonShift));
+					if(MultiSelect && HasControlOrAlt(me)) {
+						UnionSelection(hit.Value.X, hit.Value.Y);
+					} else {
+						SetSelection (hit.Value.X, hit.Value.Y, me.Flags.HasFlag (MouseFlags.ButtonShift));
+					}
+
 					Update ();
 					Update ();
 				}
 				}
 			}
 			}
@@ -1055,6 +1113,11 @@ namespace Terminal.Gui {
 			return false;
 			return false;
 		}
 		}
 
 
+		private bool HasControlOrAlt (MouseEvent me)
+		{
+			return me.Flags.HasFlag (MouseFlags.ButtonAlt) || me.Flags.HasFlag (MouseFlags.ButtonCtrl);
+		}
+
 		/// <summary>.
 		/// <summary>.
 		/// Returns the column and row of <see cref="Table"/> that corresponds to a given point 
 		/// Returns the column and row of <see cref="Table"/> that corresponds to a given point 
 		/// on the screen (relative to the control client area).  Returns null if the point is
 		/// on the screen (relative to the control client area).  Returns null if the point is

+ 1 - 0
Terminal.Gui/Views/TextField.cs

@@ -298,6 +298,7 @@ namespace Terminal.Gui {
 					}
 					}
 					return;
 					return;
 				}
 				}
+				ClearAllSelection ();
 				text = TextModel.ToRunes (newText.NewText);
 				text = TextModel.ToRunes (newText.NewText);
 
 
 				if (!Secret && !historyText.IsFromHistory) {
 				if (!Secret && !historyText.IsFromHistory) {

+ 9 - 0
Terminal.Gui/Windows/FileDialog.cs

@@ -83,6 +83,7 @@ namespace Terminal.Gui {
 				case DirectoryNotFoundException _:
 				case DirectoryNotFoundException _:
 				case ArgumentException _:
 				case ArgumentException _:
 					dirInfo = null;
 					dirInfo = null;
+					watcher?.Dispose ();
 					watcher = null;
 					watcher = null;
 					infos.Clear ();
 					infos.Clear ();
 					valid = true;
 					valid = true;
@@ -104,7 +105,15 @@ namespace Terminal.Gui {
 		{
 		{
 			if (!_disposedValue) {
 			if (!_disposedValue) {
 				if (disposing) {
 				if (disposing) {
+					if (watcher != null) {
+						watcher.Changed -= Watcher_Changed;
+						watcher.Created -= Watcher_Changed;
+						watcher.Deleted -= Watcher_Changed;
+						watcher.Renamed -= Watcher_Changed;
+						watcher.Error -= Watcher_Error;
+					}
 					watcher?.Dispose ();
 					watcher?.Dispose ();
+					watcher = null;
 				}
 				}
 
 
 				_disposedValue = true;
 				_disposedValue = true;

+ 13 - 15
UICatalog/Properties/launchSettings.json

@@ -3,10 +3,16 @@
     "UICatalog": {
     "UICatalog": {
       "commandName": "Project"
       "commandName": "Project"
     },
     },
-    "UICatalog : -usc": {
+    "UICatalog -usc": {
       "commandName": "Project",
       "commandName": "Project",
       "commandLineArgs": "-usc"
       "commandLineArgs": "-usc"
     },
     },
+    "WSL: UICatalog -usc": {
+      "commandName": "Executable",
+      "executablePath": "wsl",
+      "commandLineArgs": "dotnet UICatalog.dll -usc",
+      "distributionName": ""
+    },
     "Wizards": {
     "Wizards": {
       "commandName": "Project",
       "commandName": "Project",
       "commandLineArgs": "Wizards"
       "commandLineArgs": "Wizards"
@@ -35,20 +41,6 @@
       "commandName": "Project",
       "commandName": "Project",
       "commandLineArgs": "\"Character Map\""
       "commandLineArgs": "\"Character Map\""
     },
     },
-    "WSL2": {
-      "commandName": "Executable",
-      "executablePath": "wsl",
-      "commandLineArgs": "dotnet UICatalog.dll"
-    },
-    "WSL2 : -usc": {
-      "commandName": "Executable",
-      "executablePath": "wsl",
-      "commandLineArgs": "dotnet UICatalog.dll -usc"
-    },
-    "WSL": {
-      "commandName": "WSL2",
-      "distributionName": ""
-    },
     "All Views Tester": {
     "All Views Tester": {
       "commandName": "Project",
       "commandName": "Project",
       "commandLineArgs": "\"All Views Tester\""
       "commandLineArgs": "\"All Views Tester\""
@@ -56,6 +48,12 @@
     "Windows & FrameViews": {
     "Windows & FrameViews": {
       "commandName": "Project",
       "commandName": "Project",
       "commandLineArgs": "\"Windows & FrameViews\""
       "commandLineArgs": "\"Windows & FrameViews\""
+    },
+    "WSL : UICatalog": {
+      "commandName": "Executable",
+      "executablePath": "wsl",
+      "commandLineArgs": "dotnet UICatalog.dll",
+      "distributionName": ""
     }
     }
   }
   }
 }
 }

+ 1 - 1
UICatalog/Scenarios/Editor.cs

@@ -343,7 +343,7 @@ namespace UICatalog.Scenarios {
 		private bool CanCloseFile ()
 		private bool CanCloseFile ()
 		{
 		{
 			if (_textView.Text == _originalText) {
 			if (_textView.Text == _originalText) {
-				System.Diagnostics.Debug.Assert (!_textView.IsDirty);
+				//System.Diagnostics.Debug.Assert (!_textView.IsDirty);
 				return true;
 				return true;
 			}
 			}
 
 

+ 7 - 6
UICatalog/UICatalog.cs

@@ -4,10 +4,10 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
-using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
 using Terminal.Gui;
 using Terminal.Gui;
+using Microsoft.DotNet.PlatformAbstractions;
 using Rune = System.Rune;
 using Rune = System.Rune;
 
 
 /// <summary>
 /// <summary>
@@ -160,6 +160,7 @@ namespace UICatalog {
 			public StatusItem Numlock;
 			public StatusItem Numlock;
 			public StatusItem Scrolllock;
 			public StatusItem Scrolllock;
 			public StatusItem DriverName;
 			public StatusItem DriverName;
+			public StatusItem OS;
 
 
 			public UICatalogTopLevel ()
 			public UICatalogTopLevel ()
 			{
 			{
@@ -177,19 +178,17 @@ namespace UICatalog {
 							"About UI Catalog", () =>  MessageBox.Query ("About UI Catalog", _aboutMessage.ToString(), "_Ok"), null, null, Key.CtrlMask | Key.A),
 							"About UI Catalog", () =>  MessageBox.Query ("About UI Catalog", _aboutMessage.ToString(), "_Ok"), null, null, Key.CtrlMask | Key.A),
 					}),
 					}),
 				});
 				});
-
+				
 				Capslock = new StatusItem (Key.CharMask, "Caps", null);
 				Capslock = new StatusItem (Key.CharMask, "Caps", null);
 				Numlock = new StatusItem (Key.CharMask, "Num", null);
 				Numlock = new StatusItem (Key.CharMask, "Num", null);
 				Scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
 				Scrolllock = new StatusItem (Key.CharMask, "Scroll", null);
 				DriverName = new StatusItem (Key.CharMask, "Driver:", null);
 				DriverName = new StatusItem (Key.CharMask, "Driver:", null);
+				OS = new StatusItem (Key.CharMask, "OS:", null);
 
 
 				StatusBar = new StatusBar () {
 				StatusBar = new StatusBar () {
 					Visible = true,
 					Visible = true,
 				};
 				};
 				StatusBar.Items = new StatusItem [] {
 				StatusBar.Items = new StatusItem [] {
-					Capslock,
-					Numlock,
-					Scrolllock,
 					new StatusItem(Key.Q | Key.CtrlMask, "~CTRL-Q~ Quit", () => {
 					new StatusItem(Key.Q | Key.CtrlMask, "~CTRL-Q~ Quit", () => {
 						if (_selectedScenario is null){
 						if (_selectedScenario is null){
 							// This causes GetScenarioToRun to return null
 							// This causes GetScenarioToRun to return null
@@ -199,7 +198,7 @@ namespace UICatalog {
 							_selectedScenario.RequestStop();
 							_selectedScenario.RequestStop();
 						}
 						}
 					}),
 					}),
-					new StatusItem(Key.F10, "~F10~ Hide/Show Status Bar", () => {
+					new StatusItem(Key.F10, "~F10~ Status Bar", () => {
 						StatusBar.Visible = !StatusBar.Visible;
 						StatusBar.Visible = !StatusBar.Visible;
 						LeftPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
 						LeftPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
 						RightPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
 						RightPane.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
@@ -207,6 +206,7 @@ namespace UICatalog {
 						SetChildNeedsDisplay();
 						SetChildNeedsDisplay();
 					}),
 					}),
 					DriverName,
 					DriverName,
+					OS
 				};
 				};
 
 
 				LeftPane = new FrameView ("Categories") {
 				LeftPane = new FrameView ("Categories") {
@@ -281,6 +281,7 @@ namespace UICatalog {
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled;
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled;
 				miHeightAsBuffer.Checked = Application.HeightAsBuffer;
 				miHeightAsBuffer.Checked = Application.HeightAsBuffer;
 				DriverName.Title = $"Driver: {Driver.GetType ().Name}";
 				DriverName.Title = $"Driver: {Driver.GetType ().Name}";
+				OS.Title = $"OS: {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystem} {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersion}";
 
 
 				if (_selectedScenario != null) {
 				if (_selectedScenario != null) {
 					_selectedScenario = null;
 					_selectedScenario = null;

+ 2 - 1
UICatalog/UICatalog.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net6.0</TargetFramework>
+    <TargetFramework>net7.0</TargetFramework>
     <LangVersion>8.0</LangVersion>
     <LangVersion>8.0</LangVersion>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
@@ -20,6 +20,7 @@
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="CsvHelper" Version="30.0.1" />
     <PackageReference Include="CsvHelper" Version="30.0.1" />
+    <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />

+ 15 - 12
UnitTests/ApplicationTests.cs → UnitTests/Application/ApplicationTests.cs

@@ -9,7 +9,7 @@ using Xunit;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ApplicationTests {
 	public class ApplicationTests {
 	public class ApplicationTests {
 		public ApplicationTests ()
 		public ApplicationTests ()
 		{
 		{
@@ -45,7 +45,7 @@ namespace Terminal.Gui.Core {
 
 
 		void Init ()
 		void Init ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (SynchronizationContext.Current);
 			Assert.NotNull (SynchronizationContext.Current);
@@ -62,7 +62,7 @@ namespace Terminal.Gui.Core {
 			// Verify initial state is per spec
 			// Verify initial state is per spec
 			Pre_Init_State ();
 			Pre_Init_State ();
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			// Verify post-Init state is correct
 			// Verify post-Init state is correct
 			Post_Init_State ();
 			Post_Init_State ();
@@ -75,33 +75,36 @@ namespace Terminal.Gui.Core {
 
 
 			// Verify state is back to initial
 			// Verify state is back to initial
 			Pre_Init_State ();
 			Pre_Init_State ();
-
+#if DEBUG_IDISPOSABLE
 			// Validate there are no outstanding Responder-based instances 
 			// Validate there are no outstanding Responder-based instances 
 			// after a scenario was selected to run. This proves the main UI Catalog
 			// after a scenario was selected to run. This proves the main UI Catalog
 			// 'app' closed cleanly.
 			// 'app' closed cleanly.
 			foreach (var inst in Responder.Instances) {
 			foreach (var inst in Responder.Instances) {
 				Assert.True (inst.WasDisposed);
 				Assert.True (inst.WasDisposed);
 			}
 			}
+#endif
 		}
 		}
 
 
 		[Fact]
 		[Fact]
 		public void Init_Shutdown_Toplevel_Not_Disposed ()
 		public void Init_Shutdown_Toplevel_Not_Disposed ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			Application.Shutdown ();
 			Application.Shutdown ();
 
 
+#if DEBUG_IDISPOSABLE
 			Assert.Single (Responder.Instances);
 			Assert.Single (Responder.Instances);
 			Assert.True (Responder.Instances [0].WasDisposed);
 			Assert.True (Responder.Instances [0].WasDisposed);
+#endif
 		}
 		}
 
 
 		[Fact]
 		[Fact]
 		public void Init_Unbalanced_Throwss ()
 		public void Init_Unbalanced_Throwss ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			Toplevel topLevel = null;
 			Toplevel topLevel = null;
-			Assert.Throws<InvalidOperationException> (() => Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))));
+			Assert.Throws<InvalidOperationException> (() => Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ()));
 			Shutdown ();
 			Shutdown ();
 
 
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Top);
@@ -110,9 +113,9 @@ namespace Terminal.Gui.Core {
 
 
 			// Now try the other way
 			// Now try the other way
 			topLevel = null;
 			topLevel = null;
-			Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
 
 
-			Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))));
+			Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver ()));
 			Shutdown ();
 			Shutdown ();
 
 
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Top);
@@ -182,7 +185,7 @@ namespace Terminal.Gui.Core {
 			// NOTE: Run<T>, when called after Init has been called behaves differently than
 			// NOTE: Run<T>, when called after Init has been called behaves differently than
 			// when called if Init has not been called.
 			// when called if Init has not been called.
 			Toplevel topLevel = null;
 			Toplevel topLevel = null;
-			Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
 
 
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 			Action<Application.RunState> NewRunStateFn = (rs) => {
 			Action<Application.RunState> NewRunStateFn = (rs) => {
@@ -255,7 +258,7 @@ namespace Terminal.Gui.Core {
 			Init ();
 			Init ();
 
 
 			// Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
 			// Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
-			Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (errorHandler: null, new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))));
+			Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (errorHandler: null, new FakeDriver ()));
 
 
 			Shutdown ();
 			Shutdown ();
 
 
@@ -354,7 +357,7 @@ namespace Terminal.Gui.Core {
 			};
 			};
 
 
 			// Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
 			// Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
-			Application.Run<TestToplevel> (errorHandler: null, new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Run<TestToplevel> (errorHandler: null, new FakeDriver ());
 
 
 			Shutdown ();
 			Shutdown ();
 
 

+ 46 - 63
UnitTests/MainLoopTests.cs → UnitTests/Application/MainLoopTests.cs

@@ -13,13 +13,18 @@ using Xunit.Sdk;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ApplicationTests {
+	/// <summary>
+	/// Tests MainLoop using the FakeMainLoop.
+	/// </summary>
 	public class MainLoopTests {
 	public class MainLoopTests {
 
 
+		// TODO: Expand to test all the MainLoop implementations.
+
 		[Fact]
 		[Fact]
 		public void Constructor_Setups_Driver ()
 		public void Constructor_Setups_Driver ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			Assert.NotNull (ml.Driver);
 			Assert.NotNull (ml.Driver);
 		}
 		}
 
 
@@ -27,7 +32,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddIdle_Adds_And_Removes ()
 		public void AddIdle_Adds_And_Removes ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			Func<bool> fnTrue = () => true;
 			Func<bool> fnTrue = () => true;
 			Func<bool> fnFalse = () => false;
 			Func<bool> fnFalse = () => false;
@@ -81,7 +86,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddIdle_Function_GetsCalled_OnIteration ()
 		public void AddIdle_Function_GetsCalled_OnIteration ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn = () => {
 			Func<bool> fn = () => {
@@ -97,7 +102,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void RemoveIdle_Function_NotCalled ()
 		public void RemoveIdle_Function_NotCalled ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn = () => {
 			Func<bool> fn = () => {
@@ -113,7 +118,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddThenRemoveIdle_Function_NotCalled ()
 		public void AddThenRemoveIdle_Function_NotCalled ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn = () => {
 			Func<bool> fn = () => {
@@ -130,7 +135,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTwice_Function_CalledTwice ()
 		public void AddTwice_Function_CalledTwice ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn = () => {
 			Func<bool> fn = () => {
@@ -161,14 +166,12 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void False_Idle_Stops_It_Being_Called_Again ()
 		public void False_Idle_Stops_It_Being_Called_Again ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn1 = () => {
 			Func<bool> fn1 = () => {
 				functionCalled++;
 				functionCalled++;
-				if (functionCalled == 10) {
-					return false;
-				}
+				if (functionCalled == 10) 					return false;
 				return true;
 				return true;
 			};
 			};
 
 
@@ -176,9 +179,7 @@ namespace Terminal.Gui.Core {
 			var stopCount = 0;
 			var stopCount = 0;
 			Func<bool> fnStop = () => {
 			Func<bool> fnStop = () => {
 				stopCount++;
 				stopCount++;
-				if (stopCount == 20) {
-					ml.Stop ();
-				}
+				if (stopCount == 20) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 
 
@@ -195,7 +196,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddIdle_Twice_Returns_False_Called_Twice ()
 		public void AddIdle_Twice_Returns_False_Called_Twice ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn1 = () => {
 			Func<bool> fn1 = () => {
@@ -207,9 +208,7 @@ namespace Terminal.Gui.Core {
 			var stopCount = 0;
 			var stopCount = 0;
 			Func<bool> fnStop = () => {
 			Func<bool> fnStop = () => {
 				stopCount++;
 				stopCount++;
-				if (stopCount == 10) {
-					ml.Stop ();
-				}
+				if (stopCount == 10) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 
 
@@ -227,14 +226,12 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Run_Runs_Idle_Stop_Stops_Idle ()
 		public void Run_Runs_Idle_Stop_Stops_Idle ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var functionCalled = 0;
 			var functionCalled = 0;
 			Func<bool> fn = () => {
 			Func<bool> fn = () => {
 				functionCalled++;
 				functionCalled++;
-				if (functionCalled == 10) {
-					ml.Stop ();
-				}
+				if (functionCalled == 10) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 
 
@@ -249,11 +246,11 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_Adds_Removes_NoFaults ()
 		public void AddTimer_Adds_Removes_NoFaults ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = 100;
 			var ms = 100;
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
 				return true;
 				return true;
 			};
 			};
@@ -270,11 +267,11 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_Run_Called ()
 		public void AddTimer_Run_Called ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = 100;
 			var ms = 100;
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
 				ml.Stop ();
 				ml.Stop ();
 				return true;
 				return true;
@@ -290,16 +287,14 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public async Task AddTimer_Duplicate_Keys_Not_Allowed ()
 		public async Task AddTimer_Duplicate_Keys_Not_Allowed ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			const int ms = 100;
 			const int ms = 100;
 			object token1 = null, token2 = null;
 			object token1 = null, token2 = null;
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
-				if (callbackCount == 2) {
-					ml.Stop ();
-				}
+				if (callbackCount == 2) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 
 
@@ -322,16 +317,14 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_In_Parallel_Wont_Throw ()
 		public void AddTimer_In_Parallel_Wont_Throw ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			const int ms = 100;
 			const int ms = 100;
 			object token1 = null, token2 = null;
 			object token1 = null, token2 = null;
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
-				if (callbackCount == 2) {
-					ml.Stop ();
-				}
+				if (callbackCount == 2) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 
 
@@ -359,12 +352,12 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_Run_CalledAtApproximatelyRightTime ()
 		public void AddTimer_Run_CalledAtApproximatelyRightTime ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = TimeSpan.FromMilliseconds (50);
 			var ms = TimeSpan.FromMilliseconds (50);
 			var watch = new System.Diagnostics.Stopwatch ();
 			var watch = new System.Diagnostics.Stopwatch ();
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				watch.Stop ();
 				watch.Stop ();
 				callbackCount++;
 				callbackCount++;
 				ml.Stop ();
 				ml.Stop ();
@@ -376,7 +369,7 @@ namespace Terminal.Gui.Core {
 			ml.Run ();
 			ml.Run ();
 			// +/- 100ms should be good enuf
 			// +/- 100ms should be good enuf
 			// https://github.com/xunit/assert.xunit/pull/25
 			// https://github.com/xunit/assert.xunit/pull/25
-			Assert.Equal<TimeSpan> (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
+			Assert.Equal (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
 
 
 			Assert.True (ml.RemoveTimeout (token));
 			Assert.True (ml.RemoveTimeout (token));
 			Assert.Equal (1, callbackCount);
 			Assert.Equal (1, callbackCount);
@@ -385,12 +378,12 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_Run_CalledTwiceApproximatelyRightTime ()
 		public void AddTimer_Run_CalledTwiceApproximatelyRightTime ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = TimeSpan.FromMilliseconds (50);
 			var ms = TimeSpan.FromMilliseconds (50);
 			var watch = new System.Diagnostics.Stopwatch ();
 			var watch = new System.Diagnostics.Stopwatch ();
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
 				if (callbackCount == 2) {
 				if (callbackCount == 2) {
 					watch.Stop ();
 					watch.Stop ();
@@ -404,7 +397,7 @@ namespace Terminal.Gui.Core {
 			ml.Run ();
 			ml.Run ();
 			// +/- 100ms should be good enuf
 			// +/- 100ms should be good enuf
 			// https://github.com/xunit/assert.xunit/pull/25
 			// https://github.com/xunit/assert.xunit/pull/25
-			Assert.Equal<TimeSpan> (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
+			Assert.Equal (ms * callbackCount, watch.Elapsed, new MillisecondTolerance (100));
 
 
 			Assert.True (ml.RemoveTimeout (token));
 			Assert.True (ml.RemoveTimeout (token));
 			Assert.Equal (2, callbackCount);
 			Assert.Equal (2, callbackCount);
@@ -413,22 +406,20 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_Remove_NotCalled ()
 		public void AddTimer_Remove_NotCalled ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = TimeSpan.FromMilliseconds (50);
 			var ms = TimeSpan.FromMilliseconds (50);
 
 
 			// Force stop if 10 iterations
 			// Force stop if 10 iterations
 			var stopCount = 0;
 			var stopCount = 0;
 			Func<bool> fnStop = () => {
 			Func<bool> fnStop = () => {
 				stopCount++;
 				stopCount++;
-				if (stopCount == 10) {
-					ml.Stop ();
-				}
+				if (stopCount == 10) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 			ml.AddIdle (fnStop);
 			ml.AddIdle (fnStop);
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
 				return true;
 				return true;
 			};
 			};
@@ -442,7 +433,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void AddTimer_ReturnFalse_StopsBeingCalled ()
 		public void AddTimer_ReturnFalse_StopsBeingCalled ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = TimeSpan.FromMilliseconds (50);
 			var ms = TimeSpan.FromMilliseconds (50);
 
 
 			// Force stop if 10 iterations
 			// Force stop if 10 iterations
@@ -450,15 +441,13 @@ namespace Terminal.Gui.Core {
 			Func<bool> fnStop = () => {
 			Func<bool> fnStop = () => {
 				Thread.Sleep (10); // Sleep to enable timer to fire
 				Thread.Sleep (10); // Sleep to enable timer to fire
 				stopCount++;
 				stopCount++;
-				if (stopCount == 10) {
-					ml.Stop ();
-				}
+				if (stopCount == 10) 					ml.Stop ();
 				return true;
 				return true;
 			};
 			};
 			ml.AddIdle (fnStop);
 			ml.AddIdle (fnStop);
 
 
 			var callbackCount = 0;
 			var callbackCount = 0;
-			Func<MainLoop, bool> callback = (MainLoop loop) => {
+			Func<MainLoop, bool> callback = (loop) => {
 				callbackCount++;
 				callbackCount++;
 				return false;
 				return false;
 			};
 			};
@@ -475,7 +464,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Invoke_Adds_Idle ()
 		public void Invoke_Adds_Idle ()
 		{
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 
 			var actionCalled = 0;
 			var actionCalled = 0;
 			ml.Invoke (() => { actionCalled++; });
 			ml.Invoke (() => { actionCalled++; });
@@ -536,10 +525,8 @@ namespace Terminal.Gui.Core {
 				Application.MainLoop.Invoke (() => {
 				Application.MainLoop.Invoke (() => {
 					tf.Text = $"index{r.Next ()}";
 					tf.Text = $"index{r.Next ()}";
 					Interlocked.Increment (ref tbCounter);
 					Interlocked.Increment (ref tbCounter);
-					if (target == tbCounter) {
-						// On last increment wake up the check
+					if (target == tbCounter) 						// On last increment wake up the check
 						_wakeUp.Set ();
 						_wakeUp.Set ();
-					}
 				});
 				});
 			});
 			});
 		}
 		}
@@ -549,9 +536,7 @@ namespace Terminal.Gui.Core {
 			for (int j = 0; j < numPasses; j++) {
 			for (int j = 0; j < numPasses; j++) {
 
 
 				_wakeUp.Reset ();
 				_wakeUp.Reset ();
-				for (var i = 0; i < numIncrements; i++) {
-					Launch (r, tf, (j + 1) * numIncrements);
-				}
+				for (var i = 0; i < numIncrements; i++) 					Launch (r, tf, (j + 1) * numIncrements);
 
 
 
 
 				while (tbCounter != (j + 1) * numIncrements) // Wait for tbCounter to reach expected value
 				while (tbCounter != (j + 1) * numIncrements) // Wait for tbCounter to reach expected value
@@ -589,7 +574,7 @@ namespace Terminal.Gui.Core {
 
 
 			await task; // Propagate exception if any occurred
 			await task; // Propagate exception if any occurred
 
 
-			Assert.Equal ((numIncrements * numPasses), tbCounter);
+			Assert.Equal (numIncrements * numPasses, tbCounter);
 		}
 		}
 
 
 		private static int total;
 		private static int total;
@@ -647,9 +632,7 @@ namespace Terminal.Gui.Core {
 					Assert.True (btn.ProcessKey (new KeyEvent (Key.Enter, null)));
 					Assert.True (btn.ProcessKey (new KeyEvent (Key.Enter, null)));
 					Assert.Equal (cancel, btn.Text);
 					Assert.Equal (cancel, btn.Text);
 					Assert.Equal (one, total);
 					Assert.Equal (one, total);
-				} else if (taskCompleted) {
-					Application.RequestStop ();
-				}
+				} else if (taskCompleted) 					Application.RequestStop ();
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();

+ 13 - 7
UnitTests/RunStateTests.cs → UnitTests/Application/RunStateTests.cs

@@ -3,12 +3,13 @@ using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ApplicationTests {
 	/// <summary>
 	/// <summary>
 	/// These tests focus on Application.RunState and the various ways it can be changed.
 	/// These tests focus on Application.RunState and the various ways it can be changed.
 	/// </summary>
 	/// </summary>
@@ -26,7 +27,7 @@ namespace Terminal.Gui.Core {
 		{
 		{
 			var rs = new Application.RunState (null);
 			var rs = new Application.RunState (null);
 			Assert.Null (rs.Toplevel);
 			Assert.Null (rs.Toplevel);
-			
+
 			var top = new Toplevel ();
 			var top = new Toplevel ();
 			rs = new Application.RunState (top);
 			rs = new Application.RunState (top);
 			Assert.Equal (top, rs.Toplevel);
 			Assert.Equal (top, rs.Toplevel);
@@ -40,8 +41,9 @@ namespace Terminal.Gui.Core {
 
 
 			// Should not throw because Toplevel was null
 			// Should not throw because Toplevel was null
 			rs.Dispose ();
 			rs.Dispose ();
+#if DEBUG_IDISPOSABLE
 			Assert.True (rs.WasDisposed);
 			Assert.True (rs.WasDisposed);
-
+#endif
 			var top = new Toplevel ();
 			var top = new Toplevel ();
 			rs = new Application.RunState (top);
 			rs = new Application.RunState (top);
 			Assert.NotNull (rs);
 			Assert.NotNull (rs);
@@ -52,13 +54,15 @@ namespace Terminal.Gui.Core {
 			rs.Toplevel.Dispose ();
 			rs.Toplevel.Dispose ();
 			rs.Toplevel = null;
 			rs.Toplevel = null;
 			rs.Dispose ();
 			rs.Dispose ();
+#if DEBUG_IDISPOSABLE
 			Assert.True (rs.WasDisposed);
 			Assert.True (rs.WasDisposed);
 			Assert.True (top.WasDisposed);
 			Assert.True (top.WasDisposed);
+#endif
 		}
 		}
 
 
 		void Init ()
 		void Init ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (SynchronizationContext.Current);
 			Assert.NotNull (SynchronizationContext.Current);
@@ -67,10 +71,10 @@ namespace Terminal.Gui.Core {
 		void Shutdown ()
 		void Shutdown ()
 		{
 		{
 			Application.Shutdown ();
 			Application.Shutdown ();
+#if DEBUG_IDISPOSABLE
 			// Validate there are no outstanding RunState-based instances left
 			// Validate there are no outstanding RunState-based instances left
-			foreach (var inst in Application.RunState.Instances) {
-				Assert.True (inst.WasDisposed);
-			}
+			foreach (var inst in Application.RunState.Instances) 				Assert.True (inst.WasDisposed);
+#endif
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -95,7 +99,9 @@ namespace Terminal.Gui.Core {
 
 
 			Shutdown ();
 			Shutdown ();
 
 
+#if DEBUG_IDISPOSABLE
 			Assert.True (rs.WasDisposed);
 			Assert.True (rs.WasDisposed);
+#endif
 
 
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Top);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.MainLoop);

+ 1 - 1
UnitTests/StackExtensionsTests.cs → UnitTests/Application/StackExtensionsTests.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ApplicationTests {
 	public class StackExtensionsTests {
 	public class StackExtensionsTests {
 		[Fact]
 		[Fact]
 		public void Stack_Toplevels_CreateToplevels ()
 		public void Stack_Toplevels_CreateToplevels ()

+ 1 - 1
UnitTests/SynchronizatonContextTests.cs → UnitTests/Application/SynchronizatonContextTests.cs

@@ -13,7 +13,7 @@ using Xunit.Sdk;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ApplicationTests {
 	public class SyncrhonizationContextTests {
 	public class SyncrhonizationContextTests {
 
 
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]

+ 0 - 324
UnitTests/ClipboardTests.cs

@@ -1,324 +0,0 @@
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using Xunit;
-
-namespace Terminal.Gui.Core {
-	public class ClipboardTests {
-		[Fact]
-		[AutoInitShutdown]
-		public void Contents_Gets_Sets ()
-		{
-			var clipText = "This is a clipboard unit test.";
-			Clipboard.Contents = clipText;
-
-			Application.Iteration += () => Application.RequestStop ();
-
-			Application.Run ();
-
-			Assert.Equal (clipText, Clipboard.Contents);
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void IsSupported_Get ()
-		{
-			if (Clipboard.IsSupported) {
-				Assert.True (Clipboard.IsSupported);
-			} else {
-				Assert.False (Clipboard.IsSupported);
-			}
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void TryGetClipboardData_Gets_From_OS_Clipboard ()
-		{
-			var clipText = "Trying to get from the OS clipboard.";
-			Clipboard.Contents = clipText;
-
-			Application.Iteration += () => Application.RequestStop ();
-
-			Application.Run ();
-
-			if (Clipboard.IsSupported) {
-				Assert.True (Clipboard.TryGetClipboardData (out string result));
-				Assert.Equal (clipText, result);
-			} else {
-				Assert.False (Clipboard.TryGetClipboardData (out string result));
-				Assert.NotEqual (clipText, result);
-			}
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void TrySetClipboardData_Sets_The_OS_Clipboard ()
-		{
-			var clipText = "Trying to set the OS clipboard.";
-			if (Clipboard.IsSupported) {
-				Assert.True (Clipboard.TrySetClipboardData (clipText));
-			} else {
-				Assert.False (Clipboard.TrySetClipboardData (clipText));
-			}
-
-			Application.Iteration += () => Application.RequestStop ();
-
-			Application.Run ();
-
-			if (Clipboard.IsSupported) {
-				Assert.Equal (clipText, Clipboard.Contents);
-			} else {
-				Assert.NotEqual (clipText, Clipboard.Contents);
-			}
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void Contents_Gets_From_OS_Clipboard ()
-		{
-			var clipText = "This is a clipboard unit test to get clipboard from OS.";
-			var exit = false;
-			var getClipText = "";
-
-			Application.Iteration += () => {
-				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
-					// using (Process clipExe = new Process {
-					// 	StartInfo = new ProcessStartInfo {
-					// 		RedirectStandardInput = true,
-					// 		FileName = "clip"
-					// 	}
-					// }) {
-					// 	clipExe.Start ();
-					// 	clipExe.StandardInput.Write (clipText);
-					// 	clipExe.StandardInput.Close ();
-					// 	var result = clipExe.WaitForExit (500);
-					// 	if (result) {
-					// 		clipExe.WaitForExit ();
-					// 	}
-					// }
-
-					using (Process pwsh = new Process {
-						StartInfo = new ProcessStartInfo {
-							FileName = "powershell",
-							Arguments = $"-command \"Set-Clipboard -Value \\\"{clipText}\\\"\""
-						}
-					}) {
-						pwsh.Start ();
-						pwsh.WaitForExit ();
-					}
-					getClipText = Clipboard.Contents.ToString ();
-
-				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
-					using (Process copy = new Process {
-						StartInfo = new ProcessStartInfo {
-							RedirectStandardInput = true,
-							FileName = "pbcopy"
-						}
-					}) {
-						copy.Start ();
-						copy.StandardInput.Write (clipText);
-						copy.StandardInput.Close ();
-						copy.WaitForExit ();
-					}
-					getClipText = Clipboard.Contents.ToString ();
-
-				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
-					if (Is_WSL_Platform ()) {
-						try {
-							using (Process bash = new Process {
-								StartInfo = new ProcessStartInfo {
-									FileName = "powershell.exe",
-									Arguments = $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\""
-								}
-							}) {
-								bash.Start ();
-								bash.WaitForExit ();
-							}
-
-							//using (Process clipExe = new Process {
-							//	StartInfo = new ProcessStartInfo {
-							//		RedirectStandardInput = true,
-							//		FileName = "clip.exe"
-							//	}
-							//}) {
-							//	clipExe.Start ();
-							//	clipExe.StandardInput.Write (clipText);
-							//	clipExe.StandardInput.Close ();
-							//	clipExe.WaitForExit ();
-							//	//var result = clipExe.WaitForExit (500);
-							//	//if (result) {
-							//	//	clipExe.WaitForExit ();
-							//	//}
-							//}
-						} catch {
-							exit = true;
-						}
-						if (!exit) {
-							getClipText = Clipboard.Contents.ToString ();
-						}
-						Application.RequestStop ();
-						return;
-					}
-					if (exit = xclipExists () == false) {
-						// xclip doesn't exist then exit.
-						Application.RequestStop ();
-						return;
-					}
-
-					using (Process bash = new Process {
-						StartInfo = new ProcessStartInfo {
-							FileName = "bash",
-							Arguments = $"-c \"xclip -sel clip -i\"",
-							RedirectStandardInput = true,
-						}
-					}) {
-						bash.Start ();
-						bash.StandardInput.Write (clipText);
-						bash.StandardInput.Close ();
-						bash.WaitForExit ();
-					}
-					if (!exit) {
-						getClipText = Clipboard.Contents.ToString ();
-					}
-				}
-
-				Application.RequestStop ();
-			};
-
-			Application.Run ();
-
-			if (!exit) {
-				Assert.Equal (clipText, getClipText);
-			}
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void Contents_Sets_The_OS_Clipboard ()
-		{
-			var clipText = "This is a clipboard unit test to set the OS clipboard.";
-			var clipReadText = "";
-			var exit = false;
-
-			Application.Iteration += () => {
-				Clipboard.Contents = clipText;
-
-				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
-					using (Process pwsh = new Process {
-						StartInfo = new ProcessStartInfo {
-							RedirectStandardOutput = true,
-							FileName = "powershell.exe",
-							Arguments = "-noprofile -command \"Get-Clipboard\""
-						}
-					}) {
-						pwsh.Start ();
-						clipReadText = pwsh.StandardOutput.ReadToEnd ().TrimEnd ();
-						pwsh.StandardOutput.Close ();
-						pwsh.WaitForExit ();
-					}
-				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
-					using (Process paste = new Process {
-						StartInfo = new ProcessStartInfo {
-							RedirectStandardOutput = true,
-							FileName = "pbpaste"
-						}
-					}) {
-						paste.Start ();
-						clipReadText = paste.StandardOutput.ReadToEnd ();
-						paste.StandardOutput.Close ();
-						paste.WaitForExit ();
-					}
-				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
-					if (Is_WSL_Platform ()) {
-						try {
-							using (Process bash = new Process {
-								StartInfo = new ProcessStartInfo {
-									RedirectStandardOutput = true,
-									FileName = "powershell.exe",
-									Arguments = "-noprofile -command \"Get-Clipboard\""
-								}
-							}) {
-								bash.Start ();
-								clipReadText = bash.StandardOutput.ReadToEnd ();
-								bash.StandardOutput.Close ();
-								bash.WaitForExit ();
-							}
-						} catch {
-							exit = true;
-						}
-						Application.RequestStop ();
-					}
-					if (exit = xclipExists () == false) {
-						// xclip doesn't exist then exit.
-						Application.RequestStop ();
-					}
-
-					using (Process bash = new Process {
-						StartInfo = new ProcessStartInfo {
-							RedirectStandardOutput = true,
-							FileName = "bash",
-							Arguments = $"-c \"xclip -sel clip -o\""
-						}
-					}) {
-						bash.Start ();
-						clipReadText = bash.StandardOutput.ReadToEnd ();
-						bash.StandardOutput.Close ();
-						bash.WaitForExit ();
-					}
-				}
-
-				Application.RequestStop ();
-			};
-
-			Application.Run ();
-
-			if (!exit) {
-				Assert.Equal (clipText, clipReadText);
-			}
-		}
-
-		bool Is_WSL_Platform ()
-		{
-			using (Process bash = new Process {
-				StartInfo = new ProcessStartInfo {
-					FileName = "bash",
-					Arguments = $"-c \"uname -a\"",
-					RedirectStandardOutput = true,
-				}
-			}) {
-				bash.Start ();
-				var result = bash.StandardOutput.ReadToEnd ();
-				var isWSL = false;
-				if (result.Contains ("microsoft") && result.Contains ("WSL")) {
-					isWSL = true;
-				}
-				bash.StandardOutput.Close ();
-				bash.WaitForExit ();
-				return isWSL;
-			}
-		}
-
-		bool xclipExists ()
-		{
-			try {
-				using (Process bash = new Process {
-					StartInfo = new ProcessStartInfo {
-						FileName = "bash",
-						Arguments = $"-c \"which xclip\"",
-						RedirectStandardOutput = true,
-					}
-				}) {
-					bash.Start ();
-					bool exist = bash.StandardOutput.ReadToEnd ().TrimEnd () != "";
-					bash.StandardOutput.Close ();
-					bash.WaitForExit ();
-					if (exist) {
-						return true;
-					}
-				}
-				return false;
-			} catch (System.Exception) {
-				return false;
-			}
-		}
-	}
-}

+ 1 - 1
UnitTests/BorderTests.cs → UnitTests/Core/BorderTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Rune = System.Rune;
 using Rune = System.Rune;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.CoreTests {
 	public class BorderTests {
 	public class BorderTests {
 		[Fact]
 		[Fact]
 		[AutoInitShutdown]
 		[AutoInitShutdown]

+ 1 - 6
UnitTests/ResponderTests.cs → UnitTests/Core/ResponderTests.cs

@@ -1,14 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Terminal.Gui;
 using Xunit;
 using Xunit;
-using static Terminal.Gui.Core.ViewTests;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.CoreTests {
 	public class ResponderTests {
 	public class ResponderTests {
 		[Fact]
 		[Fact]
 		public void New_Initializes ()
 		public void New_Initializes ()

+ 5 - 5
UnitTests/AttributeTests.cs → UnitTests/Drivers/AttributeTests.cs

@@ -7,13 +7,13 @@ using Xunit;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.ConsoleDrivers {
+namespace Terminal.Gui.DriverTests {
 	public class AttributeTests {
 	public class AttributeTests {
 		[Fact]
 		[Fact]
 		public void Constuctors_Constuct ()
 		public void Constuctors_Constuct ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			// Test parameterless constructor
 			// Test parameterless constructor
@@ -59,7 +59,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Implicit_Assign ()
 		public void Implicit_Assign ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			var attr = new Attribute ();
 			var attr = new Attribute ();
@@ -100,7 +100,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Make_Creates ()
 		public void Make_Creates ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			var fg = new Color ();
 			var fg = new Color ();
@@ -128,7 +128,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Get_Gets ()
 		public void Get_Gets ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			var value = 42;
 			var value = 42;

+ 288 - 0
UnitTests/Drivers/ClipboardTests.cs

@@ -0,0 +1,288 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Terminal.Gui;
+using Xunit;
+using Xunit.Abstractions;
+using static AutoInitShutdownAttribute;
+
+namespace Terminal.Gui.DriverTests {
+	public class ClipboardTests {
+		readonly ITestOutputHelper output;
+
+		public ClipboardTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
+		public void IClipboard_GetClipBoardData_Throws_NotSupportedException ()
+		{
+			IClipboard iclip = Application.Driver.Clipboard;
+			Assert.Throws<NotSupportedException> (() => iclip.GetClipboardData ());
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardAlwaysThrowsNotSupportedException: true)]
+		public void IClipboard_SetClipBoardData_Throws_NotSupportedException ()
+		{
+			IClipboard iclip = Application.Driver.Clipboard;
+			Assert.Throws<NotSupportedException> (() => iclip.SetClipboardData ("foo"));
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: true)]
+		public void Contents_Fake_Gets_Sets ()
+		{
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
+			Clipboard.Contents = clipText;
+
+			Application.Iteration += () => Application.RequestStop ();
+			Application.Run ();
+
+			Assert.Equal (clipText, Clipboard.Contents.ToString ());
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void Contents_Gets_Sets ()
+		{
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
+			Clipboard.Contents = clipText;
+
+			Application.Iteration += () => Application.RequestStop ();
+			Application.Run ();
+
+			Assert.Equal (clipText, Clipboard.Contents.ToString ());
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void Contents_Gets_Sets_When_IsSupportedFalse ()
+		{
+
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
+			Clipboard.Contents = clipText;
+
+			Application.Iteration += () => Application.RequestStop ();
+			Application.Run ();
+
+			Assert.Equal (clipText, Clipboard.Contents.ToString ());
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: true)]
+		public void Contents_Fake_Gets_Sets_When_IsSupportedFalse ()
+		{
+
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Gets_Sets unit test pasted this to the OS clipboard.";
+			Clipboard.Contents = clipText;
+
+			Application.Iteration += () => Application.RequestStop ();
+			Application.Run ();
+
+			Assert.Equal (clipText, Clipboard.Contents.ToString ());
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void IsSupported_Get ()
+		{
+			if (Clipboard.IsSupported) 				Assert.True (Clipboard.IsSupported);
+else 				Assert.False (Clipboard.IsSupported);
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void TryGetClipboardData_Gets_From_OS_Clipboard ()
+		{
+			var clipText = "The TryGetClipboardData_Gets_From_OS_Clipboard unit test pasted this to the OS clipboard.";
+			Clipboard.Contents = clipText;
+
+			Application.Iteration += () => Application.RequestStop ();
+
+			Application.Run ();
+
+			if (Clipboard.IsSupported) {
+				Assert.True (Clipboard.TryGetClipboardData (out string result));
+				Assert.Equal (clipText, result);
+			} else {
+				Assert.False (Clipboard.TryGetClipboardData (out string result));
+				Assert.NotEqual (clipText, result);
+			}
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void TrySetClipboardData_Sets_The_OS_Clipboard ()
+		{
+			var clipText = "The TrySetClipboardData_Sets_The_OS_Clipboard unit test pasted this to the OS clipboard.";
+			if (Clipboard.IsSupported) 				Assert.True (Clipboard.TrySetClipboardData (clipText));
+else 				Assert.False (Clipboard.TrySetClipboardData (clipText));
+
+			Application.Iteration += () => Application.RequestStop ();
+
+			Application.Run ();
+
+			if (Clipboard.IsSupported) 				Assert.Equal (clipText, Clipboard.Contents);
+else 				Assert.NotEqual (clipText, Clipboard.Contents);
+		}
+
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void Contents_Copies_From_OS_Clipboard ()
+		{
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Copies_From_OS_Clipboard unit test pasted this to the OS clipboard.";
+			var failed = false;
+			var getClipText = "";
+
+			Application.Iteration += () => {
+				int exitCode = 0;
+				string result = "";
+				output.WriteLine ($"Pasting to OS clipboard: {clipText}...");
+
+				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+					(exitCode, result) = ClipboardProcessRunner.Process ("pwsh", $"-command \"Set-Clipboard -Value \\\"{clipText}\\\"\"");
+					output.WriteLine ($"  Windows: pwsh Set-Clipboard: exitCode = {exitCode}, result = {result}");
+					getClipText = Clipboard.Contents.ToString ();
+
+				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
+					(exitCode, result) = ClipboardProcessRunner.Process ("pbcopy", string.Empty, clipText);
+					output.WriteLine ($"  OSX: pbcopy: exitCode = {exitCode}, result = {result}");
+					getClipText = Clipboard.Contents.ToString ();
+
+				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
+					if (Is_WSL_Platform ()) {
+						try {
+							// This runs the WINDOWS version of powershell.exe via WSL.
+							(exitCode, result) = ClipboardProcessRunner.Process ("powershell.exe", $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\"");
+							output.WriteLine ($"  WSL: powershell.exe Set-Clipboard: exitCode = {exitCode}, result = {result}");
+						} catch {
+							failed = true;
+						}
+
+						if (!failed) {
+							// If we set the OS clipboard via Powershell, then getting Contents should return the same text.
+							getClipText = Clipboard.Contents.ToString ();
+							output.WriteLine ($"  WSL: Clipboard.Contents: {getClipText}");
+						}
+						Application.RequestStop ();
+						return;
+					}
+
+					if (failed = xclipExists () == false) {
+						// if xclip doesn't exist then exit.
+						output.WriteLine ($"  WSL: no xclip found.");
+						Application.RequestStop ();
+						return;
+					}
+
+					// If we get here, powershell didn't work and xclip exists...
+					(exitCode, result) = ClipboardProcessRunner.Process ("bash", $"-c \"xclip -sel clip -i\"", clipText);
+					output.WriteLine ($"  Linux: bash xclip -sel clip -i: exitCode = {exitCode}, result = {result}");
+
+					if (!failed) {
+						getClipText = Clipboard.Contents.ToString ();
+						output.WriteLine ($"  Linux via xclip: Clipboard.Contents: {getClipText}");
+					}
+				}
+
+				Application.RequestStop ();
+			};
+
+			Application.Run ();
+
+			if (!failed) 				Assert.Equal (clipText, getClipText);
+		}
+
+		[Fact, AutoInitShutdown (useFakeClipboard: false)]
+		public void Contents_Pastes_To_OS_Clipboard ()
+		{
+			if (!Clipboard.IsSupported) {
+				output.WriteLine ($"The Clipboard not supported on this platform.");
+				return;
+			}
+
+			var clipText = "The Contents_Pastes_To_OS_Clipboard unit test pasted this via Clipboard.Contents.";
+			var clipReadText = "";
+			var failed = false;
+
+			Application.Iteration += () => {
+				Clipboard.Contents = clipText;
+
+				int exitCode = 0;
+				output.WriteLine ($"Getting OS clipboard...");
+
+				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+					(exitCode, clipReadText) = ClipboardProcessRunner.Process ("pwsh", "-noprofile -command \"Get-Clipboard\"");
+					output.WriteLine ($"  Windows: pwsh Get-Clipboard: exitCode = {exitCode}, result = {clipReadText}");
+
+				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
+					(exitCode, clipReadText) = ClipboardProcessRunner.Process ("pbpaste", "");
+					output.WriteLine ($"  OSX: pbpaste: exitCode = {exitCode}, result = {clipReadText}");
+
+				} else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
+					if (Is_WSL_Platform ()) {
+						(exitCode, clipReadText) = ClipboardProcessRunner.Process ("powershell.exe", "-noprofile -command \"Get-Clipboard\"");
+						output.WriteLine ($"  WSL: powershell.exe Get-Clipboard: exitCode = {exitCode}, result = {clipReadText}");
+						if (exitCode == 0) {
+							Application.RequestStop ();
+							return;
+						}
+						failed = true;
+					}
+
+					if (failed = xclipExists () == false) {
+						// xclip doesn't exist then exit.
+						Application.RequestStop ();
+						return;
+					}
+
+					(exitCode, clipReadText) = ClipboardProcessRunner.Process ("bash", $"-c \"xclip -sel clip -o\"");
+					output.WriteLine ($"  Linux: bash xclip -sel clip -o: exitCode = {exitCode}, result = {clipReadText}");
+					Assert.Equal (0, exitCode);
+				}
+
+				Application.RequestStop ();
+			};
+
+			Application.Run ();
+
+			if (!failed) 				Assert.Equal (clipText, clipReadText.TrimEnd ());
+
+		}
+
+		bool Is_WSL_Platform ()
+		{
+			var (_, result) = ClipboardProcessRunner.Process ("bash", $"-c \"uname -a\"");
+			return result.Contains ("microsoft") && result.Contains ("WSL");
+		}
+
+		bool xclipExists ()
+		{
+			try {
+				var (_, result) = ClipboardProcessRunner.Process ("bash", $"-c \"which xclip\"");
+				return result.TrimEnd () != "";
+			} catch (Exception) {
+				return false;
+			}
+		}
+	}
+}

+ 39 - 0
UnitTests/Drivers/ColorTests.cs

@@ -0,0 +1,39 @@
+using System;
+using Xunit;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.DriverTests {
+	public class ColorTests {
+
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		//[InlineData (typeof (NetDriver))]
+		//[InlineData (typeof (CursesDriver))]
+		//[InlineData (typeof (WindowsDriver))]
+		public void SetColors_Changes_Colors (Type driverType)
+		{
+			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
+			driver.Init (() => { });
+			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
+			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
+
+			Console.ForegroundColor = ConsoleColor.Red;
+			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
+
+			Console.BackgroundColor = ConsoleColor.Green;
+			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
+
+			Console.ResetColor ();
+			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 ();
+		}
+
+	}
+}

+ 72 - 280
UnitTests/ConsoleDriverTests.cs → UnitTests/Drivers/ConsoleDriverTests.cs

@@ -2,14 +2,13 @@
 using System.Collections;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
-using Terminal.Gui.Views;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.ConsoleDrivers {
+namespace Terminal.Gui.DriverTests {
 	public class ConsoleDriverTests {
 	public class ConsoleDriverTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -18,11 +17,15 @@ namespace Terminal.Gui.ConsoleDrivers {
 			this.output = output;
 			this.output = output;
 		}
 		}
 
 
-		[Fact]
-		public void Init_Inits ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		//[InlineData (typeof (NetDriver))]
+		//[InlineData (typeof (CursesDriver))]
+		//[InlineData (typeof (WindowsDriver))]
+		public void Init_Inits (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			Assert.Equal (80, Console.BufferWidth);
 			Assert.Equal (80, Console.BufferWidth);
@@ -37,17 +40,21 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void End_Cleans_Up ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		//[InlineData (typeof (NetDriver))]
+		//[InlineData (typeof (CursesDriver))]
+		//[InlineData (typeof (WindowsDriver))]
+		public void End_Cleans_Up (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
-			FakeConsole.ForegroundColor = ConsoleColor.Red;
+			Console.ForegroundColor = ConsoleColor.Red;
 			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
 
 
-			FakeConsole.BackgroundColor = ConsoleColor.Green;
+			Console.BackgroundColor = ConsoleColor.Green;
 			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
 			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
 			driver.Move (2, 3);
 			driver.Move (2, 3);
 			Assert.Equal (2, Console.CursorLeft);
 			Assert.Equal (2, Console.CursorLeft);
@@ -63,34 +70,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void SetColors_Changes_Colors ()
-		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-			driver.Init (() => { });
-			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
-			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
-
-			Console.ForegroundColor = ConsoleColor.Red;
-			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
-
-			Console.BackgroundColor = ConsoleColor.Green;
-			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
-
-			Console.ResetColor ();
-			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]
-		public void FakeDriver_Only_Sends_Keystrokes_Through_MockKeyPresses ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void FakeDriver_Only_Sends_Keystrokes_Through_MockKeyPresses (Type driverType)
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 			var view = new View ();
 			var view = new View ();
@@ -104,9 +89,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
 				count++;
 				count++;
-				if (count == 10) {
-					Application.RequestStop ();
-				}
+				if (count == 10) Application.RequestStop ();
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();
@@ -117,10 +100,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void FakeDriver_MockKeyPresses ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void FakeDriver_MockKeyPresses (Type driverType)
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			var text = "MockKeyPresses";
 			var text = "MockKeyPresses";
 			var mKeys = new Stack<ConsoleKeyInfo> ();
 			var mKeys = new Stack<ConsoleKeyInfo> ();
@@ -129,7 +114,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 				var cki = new ConsoleKeyInfo (r, ck, false, false, false);
 				var cki = new ConsoleKeyInfo (r, ck, false, false, false);
 				mKeys.Push (cki);
 				mKeys.Push (cki);
 			}
 			}
-			FakeConsole.MockKeyPresses = mKeys;
+			Console.MockKeyPresses = mKeys;
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 			var view = new View ();
 			var view = new View ();
@@ -146,9 +131,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 			top.Add (view);
 			top.Add (view);
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
-				if (mKeys.Count == 0) {
-					Application.RequestStop ();
-				}
+				if (mKeys.Count == 0) Application.RequestStop ();
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();
@@ -159,108 +142,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void SendKeys_Test ()
-		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-
-			var top = Application.Top;
-			var view = new View ();
-			var shift = false; var alt = false; var control = false;
-			Key key = default;
-			Key lastKey = default;
-			List<Key> keyEnums = GetKeys ();
-			int i = 0;
-			int idxKey = 0;
-			var PushIterations = 0;
-			var PopIterations = 0;
-
-			List<Key> GetKeys ()
-			{
-				List<Key> keys = new List<Key> ();
-
-				foreach (Key k in Enum.GetValues (typeof (Key))) {
-					if ((uint)k <= 0xff) {
-						keys.Add (k);
-					} else if ((uint)k > 0xff) {
-						break;
-					}
-				}
-
-				return keys;
-			}
-
-			view.KeyPress += (e) => {
-				e.Handled = true;
-				PopIterations++;
-				var rMk = new KeyModifiers () {
-					Shift = e.KeyEvent.IsShift,
-					Alt = e.KeyEvent.IsAlt,
-					Ctrl = e.KeyEvent.IsCtrl
-				};
-				lastKey = ShortcutHelper.GetModifiersKey (new KeyEvent (e.KeyEvent.Key, rMk));
-				Assert.Equal (key, lastKey);
-			};
-			top.Add (view);
-
-			Application.Iteration += () => {
-				switch (i) {
-				case 0:
-					SendKeys ();
-					break;
-				case 1:
-					shift = true;
-					SendKeys ();
-					break;
-				case 2:
-					alt = true;
-					SendKeys ();
-					break;
-				case 3:
-					control = true;
-					SendKeys ();
-					break;
-				}
-				if (PushIterations == keyEnums.Count * 4) {
-					Application.RequestStop ();
-				}
-			};
-
-			void SendKeys ()
-			{
-				var k = shift && char.IsLetter ((char)keyEnums [idxKey]) && char.IsLower ((char)keyEnums [idxKey])
-					? (Key)char.ToUpper ((char)keyEnums [idxKey]) : keyEnums [idxKey];
-				var c = (char)k;
-				var ck = char.IsLetter (c) ? (ConsoleKey)char.ToUpper (c) : (ConsoleKey)c;
-				var mk = new KeyModifiers () {
-					Shift = shift,
-					Alt = alt,
-					Ctrl = control
-				};
-				key = ShortcutHelper.GetModifiersKey (new KeyEvent (k, mk));
-				Application.Driver.SendKeys (c, ck, shift, alt, control);
-				PushIterations++;
-				if (idxKey + 1 < keyEnums.Count) {
-					idxKey++;
-				} else {
-					idxKey = 0;
-					i++;
-				}
-			}
-
-			Application.Run ();
-
-			Assert.Equal (key, lastKey);
-
-			// Shutdown must be called to safely clean up Application if Init has been called
-			Application.Shutdown ();
-		}
-
-		[Fact]
-		public void TerminalResized_Simulation ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void TerminalResized_Simulation (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 			var wasTerminalResized = false;
 			var wasTerminalResized = false;
 			Application.Resized = (e) => {
 			Application.Resized = (e) => {
 				wasTerminalResized = true;
 				wasTerminalResized = true;
@@ -297,11 +184,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void HeightAsBuffer_Is_False_Left_And_Top_Is_Always_Zero ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void HeightAsBuffer_Is_False_Left_And_Top_Is_Always_Zero (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			Assert.False (Application.HeightAsBuffer);
 			Assert.False (Application.HeightAsBuffer);
 			Assert.Equal (0, Console.WindowLeft);
 			Assert.Equal (0, Console.WindowLeft);
@@ -314,11 +202,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			Application.HeightAsBuffer = true;
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
 			Assert.True (Application.HeightAsBuffer);
@@ -330,11 +219,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			Application.HeightAsBuffer = true;
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
 			Assert.True (Application.HeightAsBuffer);
@@ -369,11 +259,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			Application.HeightAsBuffer = true;
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
 			Assert.True (Application.HeightAsBuffer);
@@ -385,11 +276,12 @@ namespace Terminal.Gui.ConsoleDrivers {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Fact]
-		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight ()
+		[Theory]
+		[InlineData (typeof (FakeDriver))]
+		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight (Type driverType)
 		{
 		{
-			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var driver = (FakeDriver)Activator.CreateInstance (driverType);
+			Application.Init (driver);
 
 
 			Application.HeightAsBuffer = true;
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
 			Assert.True (Application.HeightAsBuffer);
@@ -427,93 +319,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 
 
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
-
-		[Fact]
-		public void Internal_Tests ()
-		{
-			var cs = new ColorScheme ();
-			Assert.Equal ("", cs.caller);
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void KeyModifiers_Resetting_At_New_Keystrokes ()
-		{
-			bool? okInitialFocused = null;
-			bool? cancelInitialFocused = null;
-			var okClicked = false;
-			var closing = false;
-			var cursorRight = false;
-			var endingKeyPress = false;
-			var closed = false;
-
-			var top = Application.Top;
-
-			var ok = new Button ("Ok");
-			ok.Clicked += () => {
-				if (!okClicked) {
-					okClicked = true;
-					Application.RequestStop ();
-				}
-			};
-
-			var cancel = new Button ("Cancel");
-
-			var d = new Dialog ("Quit", cancel, ok);
-			d.KeyPress += (e) => {
-				if (e.KeyEvent.Key == (Key.Q | Key.CtrlMask)) {
-					if (!okClicked && !closing) {
-						okInitialFocused = ok.HasFocus;
-						cancelInitialFocused = cancel.HasFocus;
-						closing = true;
-						var mKeys = new Stack<ConsoleKeyInfo> ();
-						var cki = new ConsoleKeyInfo ('\0', ConsoleKey.Enter, false, false, false);
-						mKeys.Push (cki);
-						cki = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, false, false, false);
-						mKeys.Push (cki);
-						FakeConsole.MockKeyPresses = mKeys;
-					}
-					e.Handled = true;
-				} else if (e.KeyEvent.Key == Key.CursorRight) {
-					if (!cursorRight) {
-						cursorRight = true;
-					} else if (ok.HasFocus) {
-						e.Handled = endingKeyPress = true;
-					}
-				}
-			};
-			d.Loaded += () => {
-				var mKeys = new Stack<ConsoleKeyInfo> ();
-				var cki = new ConsoleKeyInfo ('q', ConsoleKey.Q, false, false, true);
-				mKeys.Push (cki);
-				FakeConsole.MockKeyPresses = mKeys;
-			};
-			d.Closed += (_) => {
-				if (okClicked && closing) {
-					closed = true;
-				}
-			};
-
-			top.Ready += () => Application.Run (d);
-
-			Application.Iteration += () => {
-				if (closed) {
-					Application.RequestStop ();
-				}
-			};
-
-			Application.Run ();
-
-			Assert.False (okInitialFocused);
-			Assert.True (cancelInitialFocused);
-			Assert.True (okClicked);
-			Assert.True (closing);
-			Assert.True (cursorRight);
-			Assert.True (endingKeyPress);
-			Assert.True (closed);
-			Assert.Empty (FakeConsole.MockKeyPresses);
-		}
-
+		
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
 		public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
 		{
 		{
@@ -645,33 +451,21 @@ namespace Terminal.Gui.ConsoleDrivers {
 		[ClassData (typeof (PacketTest))]
 		[ClassData (typeof (PacketTest))]
 		public void TestVKPacket (uint unicodeCharacter, bool shift, bool alt, bool control, uint initialVirtualKey, uint initialScanCode, Key expectedRemapping, uint expectedVirtualKey, uint expectedScanCode)
 		public void TestVKPacket (uint unicodeCharacter, bool shift, bool alt, bool control, uint initialVirtualKey, uint initialScanCode, Key expectedRemapping, uint expectedVirtualKey, uint expectedScanCode)
 		{
 		{
-			ConsoleModifiers modifiers = new ConsoleModifiers ();
-			if (shift) {
-				modifiers |= ConsoleModifiers.Shift;
-			}
-			if (alt) {
-				modifiers |= ConsoleModifiers.Alt;
-			}
-			if (control) {
-				modifiers |= ConsoleModifiers.Control;
-			}
+			var modifiers = new ConsoleModifiers ();
+			if (shift) modifiers |= ConsoleModifiers.Shift;
+			if (alt) modifiers |= ConsoleModifiers.Alt;
+			if (control) modifiers |= ConsoleModifiers.Control;
 			var mappedConsoleKey = ConsoleKeyMapping.GetConsoleKeyFromKey (unicodeCharacter, modifiers, out uint scanCode, out uint outputChar);
 			var mappedConsoleKey = ConsoleKeyMapping.GetConsoleKeyFromKey (unicodeCharacter, modifiers, out uint scanCode, out uint outputChar);
 
 
-			if ((scanCode > 0 || mappedConsoleKey == 0) && mappedConsoleKey == initialVirtualKey) {
-				Assert.Equal (mappedConsoleKey, initialVirtualKey);
-			} else {
-				Assert.Equal (mappedConsoleKey, outputChar < 0xff ? (uint)(outputChar & 0xff | 0xff << 8) : outputChar);
-			}
+			if ((scanCode > 0 || mappedConsoleKey == 0) && mappedConsoleKey == initialVirtualKey) Assert.Equal (mappedConsoleKey, initialVirtualKey);
+			else Assert.Equal (mappedConsoleKey, outputChar < 0xff ? outputChar & 0xff | 0xff << 8 : outputChar);
 			Assert.Equal (scanCode, initialScanCode);
 			Assert.Equal (scanCode, initialScanCode);
 
 
 			var keyChar = ConsoleKeyMapping.GetKeyCharFromConsoleKey (mappedConsoleKey, modifiers, out uint consoleKey, out scanCode);
 			var keyChar = ConsoleKeyMapping.GetKeyCharFromConsoleKey (mappedConsoleKey, modifiers, out uint consoleKey, out scanCode);
 
 
 			//if (scanCode > 0 && consoleKey == keyChar && consoleKey > 48 && consoleKey > 57 && consoleKey < 65 && consoleKey > 91) {
 			//if (scanCode > 0 && consoleKey == keyChar && consoleKey > 48 && consoleKey > 57 && consoleKey < 65 && consoleKey > 91) {
-			if (scanCode > 0 && keyChar == 0 && consoleKey == mappedConsoleKey) {
-				Assert.Equal (0, (double)keyChar);
-			} else {
-				Assert.Equal (keyChar, unicodeCharacter);
-			}
+			if (scanCode > 0 && keyChar == 0 && consoleKey == mappedConsoleKey) Assert.Equal (0, (double)keyChar);
+			else Assert.Equal (keyChar, unicodeCharacter);
 			Assert.Equal (consoleKey, expectedVirtualKey);
 			Assert.Equal (consoleKey, expectedVirtualKey);
 			Assert.Equal (scanCode, expectedScanCode);
 			Assert.Equal (scanCode, expectedScanCode);
 
 
@@ -688,9 +482,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
 				iterations++;
 				iterations++;
-				if (iterations == 0) {
-					Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control);
-				}
+				if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control);
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();

+ 1 - 1
UnitTests/KeyTests.cs → UnitTests/Drivers/KeyTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.DriverTests {
 	public class KeyTests {
 	public class KeyTests {
 		enum SimpleEnum { Zero, One, Two, Three, Four, Five }
 		enum SimpleEnum { Zero, One, Two, Three, Four, Five }
 
 

+ 2 - 2
UnitTests/ContextMenuTests.cs → UnitTests/Menus/ContextMenuTests.cs

@@ -2,9 +2,9 @@
 using System.Threading;
 using System.Threading;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
-using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
+//using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.MenuTests {
 	public class ContextMenuTests {
 	public class ContextMenuTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 2 - 2
UnitTests/MenuTests.cs → UnitTests/Menus/MenuTests.cs

@@ -3,9 +3,9 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
-using static Terminal.Gui.Views.MenuTests;
+//using static Terminal.Gui.ViewTests.MenuTests;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.MenuTests {
 	public class MenuTests {
 	public class MenuTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 52 - 13
UnitTests/TestHelpers.cs

@@ -10,37 +10,76 @@ using Rune = System.Rune;
 using Attribute = Terminal.Gui.Attribute;
 using Attribute = Terminal.Gui.Attribute;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using System.Reflection;
 using System.Reflection;
+using System.Diagnostics;
 
 
 
 
 // This class enables test functions annotated 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
+// automatically call Application.Init at start of the test and Application.Shutdown after the
+// test exits. 
 // 
 // 
 // This is necessary because a) Application is a singleton and Init/Shutdown must be called
 // 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.
+// as a pair, and b) all unit test functions should be atomic..
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
 public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
+	/// <summary>
+	/// Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and
+	/// Application.Shutdown are automatically called Before/After a test runs.
+	/// </summary>
+	/// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
+	/// <param name="autoShutdown">If true, Application.Shutdown will be called After the test runs.</param>
+	/// <param name="consoleDriverType">Determins which ConsoleDriver (FakeDriver, WindowsDriver, 
+	/// CursesDriver, NetDriver) will be used when Appliation.Init is called. If null FakeDriver will be used.
+	/// Only valid if <paramref name="autoInit"/> is true.</param>
+	/// <param name="useFakeClipboard">If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>. 
+	/// Only valid if <see cref="consoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
+	/// <param name="fakeClipboardAlwaysThrowsNotSupportedException">Only valid if <paramref name="autoInit"/> is true.
+	/// Only valid if <see cref="consoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
+	/// <param name="fakeClipboardIsSupportedAlwaysTrue">Only valid if <paramref name="autoInit"/> is true.
+	/// Only valid if <see cref="consoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.</param>
+	public AutoInitShutdownAttribute (bool autoInit = true, bool autoShutdown = true,
+		Type consoleDriverType = null,
+		bool useFakeClipboard = false,
+		bool fakeClipboardAlwaysThrowsNotSupportedException = false,
+		bool fakeClipboardIsSupportedAlwaysTrue = false)
+	{
+		//Assert.True (autoInit == false && consoleDriverType == null);
+
+		AutoInit = autoInit;
+		AutoShutdown = autoShutdown;
+		DriverType = consoleDriverType ?? typeof (FakeDriver);
+		FakeDriver.FakeBehaviors.UseFakeClipboard = useFakeClipboard;
+		FakeDriver.FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException;
+		FakeDriver.FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue;
+	}
 
 
 	static bool _init = false;
 	static bool _init = false;
+	bool AutoInit { get; }
+	bool AutoShutdown { get; }
+	Type DriverType;
+
 	public override void Before (MethodInfo methodUnderTest)
 	public override void Before (MethodInfo methodUnderTest)
 	{
 	{
-		if (_init) {
-			throw new InvalidOperationException ("After did not run.");
+		Debug.WriteLine ($"Before: {methodUnderTest.Name}");
+		if (AutoShutdown && _init) {
+			throw new InvalidOperationException ("After did not run when AutoShutdown was specified.");
+		}
+		if (AutoInit) {
+			Application.Init ((ConsoleDriver)Activator.CreateInstance (DriverType));
+			_init = true;
 		}
 		}
-
-		Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-		_init = true;
 	}
 	}
 
 
 	public override void After (MethodInfo methodUnderTest)
 	public override void After (MethodInfo methodUnderTest)
 	{
 	{
-		Application.Shutdown ();
-		_init = false;
+		Debug.WriteLine ($"After: {methodUnderTest.Name}");
+		if (AutoShutdown) {
+			Application.Shutdown ();
+			_init = false;
+		}
 	}
 	}
 }
 }
 
 
 class TestHelpers {
 class TestHelpers {
-
-
 #pragma warning disable xUnit1013 // Public method should be marked as test
 #pragma warning disable xUnit1013 // Public method should be marked as test
 	public static void AssertDriverContentsAre (string expectedLook, ITestOutputHelper output)
 	public static void AssertDriverContentsAre (string expectedLook, ITestOutputHelper output)
 	{
 	{
@@ -212,7 +251,7 @@ class TestHelpers {
 
 
 				var match = expectedColors.Where (e => e.Value == val).ToList ();
 				var match = expectedColors.Where (e => e.Value == val).ToList ();
 				if (match.Count == 0) {
 				if (match.Count == 0) {
-					throw new Exception ($"Unexpected color {DescribeColor (val)} was used at row {r} and col {c} (indexes start at 0).  Color value was {val} (expected colors were {string.Join (",", expectedColors.Select (c => c.Value))})");
+					throw new Exception ($"Unexpected color {DescribeColor (val)} was used at row {r} and col {c} (indexes start at 0).  Color value was {val} (expected colors were {string.Join (",", expectedColors.Select (c => DescribeColor (c.Value)))})");
 				} else if (match.Count > 1) {
 				} else if (match.Count > 1) {
 					throw new ArgumentException ($"Bad value for expectedColors, {match.Count} Attributes had the same Value");
 					throw new ArgumentException ($"Bad value for expectedColors, {match.Count} Attributes had the same Value");
 				}
 				}
@@ -221,7 +260,7 @@ class TestHelpers {
 				var userExpected = line [c];
 				var userExpected = line [c];
 
 
 				if (colorUsed != userExpected) {
 				if (colorUsed != userExpected) {
-					throw new Exception ($"Colors used did not match expected at row {r} and col {c} (indexes start at 0).  Color index used was {DescribeColor (colorUsed)} but test expected {DescribeColor (userExpected)} (these are indexes into the expectedColors array)");
+					throw new Exception ($"Colors used did not match expected at row {r} and col {c} (indexes start at 0).  Color index used was {colorUsed} ({DescribeColor (val)}) but test expected {userExpected} ({DescribeColor (expectedColors [int.Parse (userExpected.ToString ())].Value)}) (these are indexes into the expectedColors array)");
 				}
 				}
 			}
 			}
 
 

+ 1 - 1
UnitTests/CollectionNavigatorTests.cs → UnitTests/Text/CollectionNavigatorTests.cs

@@ -2,7 +2,7 @@
 using System.Threading;
 using System.Threading;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TextTests {
 	public class CollectionNavigatorTests {
 	public class CollectionNavigatorTests {
 		static string [] simpleStrings = new string []{
 		static string [] simpleStrings = new string []{
 		    "appricot", // 0
 		    "appricot", // 0

+ 65 - 36
UnitTests/TextFormatterTests.cs → UnitTests/Text/TextFormatterTests.cs

@@ -2,14 +2,14 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
-using Terminal.Gui.Views;
+using Terminal.Gui;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TextTests {
 	public class TextFormatterTests {
 	public class TextFormatterTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -394,7 +394,7 @@ namespace Terminal.Gui.Core {
 			bool supportFirstUpperCase = true;
 			bool supportFirstUpperCase = true;
 
 
 			var text = ustring.Empty;
 			var text = ustring.Empty;
-			Rune hotKeySpecifier = (Rune)0;
+			var hotKeySpecifier = (Rune)0;
 			int hotPos = 0;
 			int hotPos = 0;
 			Key hotKey = Key.Unknown;
 			Key hotKey = Key.Unknown;
 			bool result = false;
 			bool result = false;
@@ -437,7 +437,7 @@ namespace Terminal.Gui.Core {
 			bool supportFirstUpperCase = true;
 			bool supportFirstUpperCase = true;
 
 
 			var text = ustring.Empty;
 			var text = ustring.Empty;
-			Rune hotKeySpecifier = (Rune)0;
+			var hotKeySpecifier = (Rune)0;
 			int hotPos = 0;
 			int hotPos = 0;
 			Key hotKey = Key.Unknown;
 			Key hotKey = Key.Unknown;
 			bool result = false;
 			bool result = false;
@@ -2162,9 +2162,7 @@ namespace Terminal.Gui.Core {
 			var height = 8;
 			var height = 8;
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var breakLines = "";
 			var breakLines = "";
-			foreach (var line in wrappedLines) {
-				breakLines += $"{line}{Environment.NewLine}";
-			}
+			foreach (var line in wrappedLines) 				breakLines += $"{line}{Environment.NewLine}";
 			var label = new Label (breakLines) { Width = Dim.Fill (), Height = Dim.Fill () };
 			var label = new Label (breakLines) { Width = Dim.Fill (), Height = Dim.Fill () };
 			var frame = new FrameView () { Width = Dim.Fill (), Height = Dim.Fill () };
 			var frame = new FrameView () { Width = Dim.Fill (), Height = Dim.Fill () };
 
 
@@ -2202,9 +2200,7 @@ namespace Terminal.Gui.Core {
 			var height = 3;
 			var height = 3;
 			var wrappedLines = TextFormatter.WordWrap (text, height, true);
 			var wrappedLines = TextFormatter.WordWrap (text, height, true);
 			var breakLines = "";
 			var breakLines = "";
-			for (int i = 0; i < wrappedLines.Count; i++) {
-				breakLines += $"{wrappedLines [i]}{(i < wrappedLines.Count - 1 ? Environment.NewLine : string.Empty)}";
-			}
+			for (int i = 0; i < wrappedLines.Count; i++) 				breakLines += $"{wrappedLines [i]}{(i < wrappedLines.Count - 1 ? Environment.NewLine : string.Empty)}";
 			var label = new Label (breakLines) {
 			var label = new Label (breakLines) {
 				TextDirection = TextDirection.TopBottom_LeftRight,
 				TextDirection = TextDirection.TopBottom_LeftRight,
 				Width = Dim.Fill (),
 				Width = Dim.Fill (),
@@ -2241,9 +2237,7 @@ namespace Terminal.Gui.Core {
 			var height = 8;
 			var height = 8;
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var breakLines = "";
 			var breakLines = "";
-			foreach (var line in wrappedLines) {
-				breakLines += $"{line}{Environment.NewLine}";
-			}
+			foreach (var line in wrappedLines) 				breakLines += $"{line}{Environment.NewLine}";
 			var label = new Label (breakLines) { Width = Dim.Fill (), Height = Dim.Fill () };
 			var label = new Label (breakLines) { Width = Dim.Fill (), Height = Dim.Fill () };
 			var frame = new FrameView () { Width = Dim.Fill (), Height = Dim.Fill () };
 			var frame = new FrameView () { Width = Dim.Fill (), Height = Dim.Fill () };
 
 
@@ -2282,9 +2276,7 @@ namespace Terminal.Gui.Core {
 			var height = 4;
 			var height = 4;
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var wrappedLines = TextFormatter.WordWrap (text, width, true);
 			var breakLines = "";
 			var breakLines = "";
-			for (int i = 0; i < wrappedLines.Count; i++) {
-				breakLines += $"{wrappedLines [i]}{(i < wrappedLines.Count - 1 ? Environment.NewLine : string.Empty)}";
-			}
+			for (int i = 0; i < wrappedLines.Count; i++) 				breakLines += $"{wrappedLines [i]}{(i < wrappedLines.Count - 1 ? Environment.NewLine : string.Empty)}";
 			var label = new Label (breakLines) {
 			var label = new Label (breakLines) {
 				TextDirection = TextDirection.TopBottom_LeftRight,
 				TextDirection = TextDirection.TopBottom_LeftRight,
 				Width = Dim.Fill (),
 				Width = Dim.Fill (),
@@ -2433,13 +2425,13 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (ustring.Make (new Rune [] { 't', tag, 's', 't' }), tf.ReplaceHotKeyWithTag (text, hotPos));
 			Assert.Equal (ustring.Make (new Rune [] { 't', tag, 's', 't' }), tf.ReplaceHotKeyWithTag (text, hotPos));
 
 
 			var result = tf.ReplaceHotKeyWithTag (text, hotPos);
 			var result = tf.ReplaceHotKeyWithTag (text, hotPos);
-			Assert.Equal ('e', (uint)(result.ToRunes () [1]));
+			Assert.Equal ('e', result.ToRunes () [1]);
 
 
 			text = "Ok";
 			text = "Ok";
 			tag = 'O';
 			tag = 'O';
 			hotPos = 0;
 			hotPos = 0;
 			Assert.Equal (ustring.Make (new Rune [] { tag, 'k' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
 			Assert.Equal (ustring.Make (new Rune [] { tag, 'k' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
-			Assert.Equal ('O', (uint)(result.ToRunes () [0]));
+			Assert.Equal ('O', result.ToRunes () [0]);
 
 
 			text = "[◦ Ok ◦]";
 			text = "[◦ Ok ◦]";
 			text = ustring.Make (new Rune [] { '[', '◦', ' ', 'O', 'k', ' ', '◦', ']' });
 			text = ustring.Make (new Rune [] { '[', '◦', ' ', 'O', 'k', ' ', '◦', ']' });
@@ -2449,13 +2441,13 @@ namespace Terminal.Gui.Core {
 			tag = 'O';
 			tag = 'O';
 			hotPos = 3;
 			hotPos = 3;
 			Assert.Equal (ustring.Make (new Rune [] { '[', '◦', ' ', tag, 'k', ' ', '◦', ']' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
 			Assert.Equal (ustring.Make (new Rune [] { '[', '◦', ' ', tag, 'k', ' ', '◦', ']' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
-			Assert.Equal ('O', (uint)(result.ToRunes () [3]));
+			Assert.Equal ('O', result.ToRunes () [3]);
 
 
 			text = "^k";
 			text = "^k";
 			tag = '^';
 			tag = '^';
 			hotPos = 0;
 			hotPos = 0;
 			Assert.Equal (ustring.Make (new Rune [] { tag, 'k' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
 			Assert.Equal (ustring.Make (new Rune [] { tag, 'k' }), result = tf.ReplaceHotKeyWithTag (text, hotPos));
-			Assert.Equal ('^', (uint)(result.ToRunes () [0]));
+			Assert.Equal ('^', result.ToRunes () [0]);
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -2814,37 +2806,37 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void System_Rune_ColumnWidth ()
 		public void System_Rune_ColumnWidth ()
 		{
 		{
-			var c = new System.Rune ('a');
+			var c = new Rune ('a');
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).Length);
 			Assert.Equal (1, ustring.Make (c).Length);
 
 
-			c = new System.Rune ('b');
+			c = new Rune ('b');
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).Length);
 			Assert.Equal (1, ustring.Make (c).Length);
 
 
-			c = new System.Rune (123);
+			c = new Rune (123);
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, Rune.ColumnWidth (c));
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).Length);
 			Assert.Equal (1, ustring.Make (c).Length);
 
 
-			c = new System.Rune ('\u1150');
+			c = new Rune ('\u1150');
 			Assert.Equal (2, Rune.ColumnWidth (c));      // 0x1150	ᅐ	Unicode Technical Report #11
 			Assert.Equal (2, Rune.ColumnWidth (c));      // 0x1150	ᅐ	Unicode Technical Report #11
 			Assert.Equal (2, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (2, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (3, ustring.Make (c).Length);
 			Assert.Equal (3, ustring.Make (c).Length);
 
 
-			c = new System.Rune ('\u1161');
+			c = new Rune ('\u1161');
 			Assert.Equal (0, Rune.ColumnWidth (c));      // 0x1161	ᅡ	column width of 0
 			Assert.Equal (0, Rune.ColumnWidth (c));      // 0x1161	ᅡ	column width of 0
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (3, ustring.Make (c).Length);
 			Assert.Equal (3, ustring.Make (c).Length);
 
 
-			c = new System.Rune (31);
+			c = new Rune (31);
 			Assert.Equal (-1, Rune.ColumnWidth (c));        // non printable character
 			Assert.Equal (-1, Rune.ColumnWidth (c));        // non printable character
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);// ConsoleWidth only returns zero or greater than zero
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);// ConsoleWidth only returns zero or greater than zero
 			Assert.Equal (1, ustring.Make (c).Length);
 			Assert.Equal (1, ustring.Make (c).Length);
 
 
-			c = new System.Rune (127);
+			c = new Rune (127);
 			Assert.Equal (-1, Rune.ColumnWidth (c));       // non printable character
 			Assert.Equal (-1, Rune.ColumnWidth (c));       // non printable character
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (0, ustring.Make (c).ConsoleWidth);
 			Assert.Equal (1, ustring.Make (c).Length);
 			Assert.Equal (1, ustring.Make (c).Length);
@@ -2896,9 +2888,7 @@ namespace Terminal.Gui.Core {
 			Assert.Equal ("nd", list1 [10].ToString ());
 			Assert.Equal ("nd", list1 [10].ToString ());
 			Assert.Equal ("Line", list1 [11].ToString ());
 			Assert.Equal ("Line", list1 [11].ToString ());
 			Assert.Equal ("- 2.", list1 [^1].ToString ());
 			Assert.Equal ("- 2.", list1 [^1].ToString ());
-			foreach (var txt in list1) {
-				wrappedText1 += txt;
-			}
+			foreach (var txt in list1) 				wrappedText1 += txt;
 			Assert.Equal (" Asentencehaswords.  This isthesecondLine- 2.", wrappedText1);
 			Assert.Equal (" Asentencehaswords.  This isthesecondLine- 2.", wrappedText1);
 
 
 			// With preserveTrailingSpaces = true.
 			// With preserveTrailingSpaces = true.
@@ -2920,9 +2910,7 @@ namespace Terminal.Gui.Core {
 			Assert.Equal ("Line", list2 [13].ToString ());
 			Assert.Equal ("Line", list2 [13].ToString ());
 			Assert.Equal (" - ", list2 [14].ToString ());
 			Assert.Equal (" - ", list2 [14].ToString ());
 			Assert.Equal ("2. ", list2 [^1].ToString ());
 			Assert.Equal ("2. ", list2 [^1].ToString ());
-			foreach (var txt in list2) {
-				wrappedText2 += txt;
-			}
+			foreach (var txt in list2) 				wrappedText2 += txt;
 			Assert.Equal (" A sentence has words.  This is the second Line - 2. ", wrappedText2);
 			Assert.Equal (" A sentence has words.  This is the second Line - 2. ", wrappedText2);
 		}
 		}
 
 
@@ -2968,7 +2956,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Draw_Horizontal_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
 		public void Draw_Horizontal_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -3008,7 +2996,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Draw_Vertical_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
 		public void Draw_Vertical_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -3430,7 +3418,7 @@ This TextFormatter (tf2) is rewritten.
 		[Fact]
 		[Fact]
 		public void GetSumMaxCharWidth_List_Simple_And_Wide_Runes ()
 		public void GetSumMaxCharWidth_List_Simple_And_Wide_Runes ()
 		{
 		{
-			List<ustring> text = new List<ustring> () { "Hello", "World" };
+			var text = new List<ustring> () { "Hello", "World" };
 			Assert.Equal (2, TextFormatter.GetSumMaxCharWidth (text));
 			Assert.Equal (2, TextFormatter.GetSumMaxCharWidth (text));
 			Assert.Equal (1, TextFormatter.GetSumMaxCharWidth (text, 1, 1));
 			Assert.Equal (1, TextFormatter.GetSumMaxCharWidth (text, 1, 1));
 			text = new List<ustring> () { "こんにちは", "世界" };
 			text = new List<ustring> () { "こんにちは", "世界" };
@@ -4259,5 +4247,46 @@ This TextFormatter (tf2) is rewritten.
 0111000000
 0111000000
 0000000000", expectedColors);
 0000000000", expectedColors);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Colors_On_TextAlignment_Right_And_Bottom ()
+		{
+			var labelRight = new Label ("Test") {
+				Width = 6,
+				Height = 1,
+				TextAlignment = TextAlignment.Right,
+				ColorScheme = Colors.Base
+			};
+			var labelBottom = new Label ("Test", TextDirection.TopBottom_LeftRight) {
+				Y = 1,
+				Width = 1,
+				Height = 6,
+				VerticalTextAlignment = VerticalTextAlignment.Bottom,
+				ColorScheme = Colors.Base
+			};
+			var top = Application.Top;
+			top.Add (labelRight, labelBottom);
+
+			Application.Begin (top);
+			((FakeDriver)Application.Driver).SetBufferSize (7, 7);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+  Test
+      
+      
+T     
+e     
+s     
+t     ", output);
+
+			TestHelpers.AssertDriverColorsAre (@"
+000000
+0
+0
+0
+0
+0
+0", new Attribute [] { Colors.Base.Normal });
+		}
 	}
 	}
 }
 }

+ 45 - 34
UnitTests/DialogTests.cs → UnitTests/TopLevels/DialogTests.cs

@@ -9,7 +9,7 @@ using System.Globalization;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using NStack;
 using NStack;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.TopLevelTests {
 
 
 	public class DialogTests {
 	public class DialogTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -29,7 +29,7 @@ namespace Terminal.Gui.Views {
 		[AutoInitShutdown]
 		[AutoInitShutdown]
 		public void ButtonAlignment_One ()
 		public void ButtonAlignment_One ()
 		{
 		{
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
 			var title = "1234";
 			var title = "1234";
@@ -37,8 +37,8 @@ namespace Terminal.Gui.Views {
 			var btnText = "ok";
 			var btnText = "ok";
 			var buttonRow = $"{d.VLine}   {d.LeftBracket} {btnText} {d.RightBracket}   {d.VLine}";
 			var buttonRow = $"{d.VLine}   {d.LeftBracket} {btnText} {d.RightBracket}   {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 
 
 			d.SetBufferSize (width, 3);
 			d.SetBufferSize (width, 3);
 
 
@@ -74,7 +74,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			// E.g "|[ yes ][ no ]|"
 			// E.g "|[ yes ][ no ]|"
@@ -85,8 +85,8 @@ namespace Terminal.Gui.Views {
 
 
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {d.VLine}";
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 
 
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
@@ -123,7 +123,7 @@ namespace Terminal.Gui.Views {
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 			bool firstIteration = false;
 			bool firstIteration = false;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			// E.g "|[ yes ][ no ]|"
 			// E.g "|[ yes ][ no ]|"
@@ -134,8 +134,8 @@ namespace Terminal.Gui.Views {
 
 
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {d.VLine}";
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 
 
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
@@ -191,7 +191,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			// E.g "|[ yes ][ no ][ maybe ]|"
 			// E.g "|[ yes ][ no ][ maybe ]|"
@@ -204,8 +204,8 @@ namespace Terminal.Gui.Views {
 
 
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {btn3} {d.VLine}";
 			var buttonRow = $@"{d.VLine} {btn1} {btn2} {btn3} {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 
 
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
@@ -241,7 +241,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 
 
@@ -257,8 +257,8 @@ namespace Terminal.Gui.Views {
 
 
 			var buttonRow = $"{d.VLine} {btn1} {btn2} {btn3} {btn4} {d.VLine}";
 			var buttonRow = $"{d.VLine} {btn1} {btn2} {btn3} {btn4} {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
 			// Default - Center
 			// Default - Center
@@ -294,7 +294,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 
 
@@ -349,7 +349,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 
 
@@ -368,8 +368,8 @@ namespace Terminal.Gui.Views {
 			//                         12345                           123456
 			//                         12345                           123456
 			var buttonRow = $"{d.VLine}     {btn1} {btn2} {btn3} {btn4}      {d.VLine}";
 			var buttonRow = $"{d.VLine}     {btn1} {btn2} {btn3} {btn4}      {d.VLine}";
 			var width = ustring.Make (buttonRow).ConsoleWidth;
 			var width = ustring.Make (buttonRow).ConsoleWidth;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 			d.SetBufferSize (width, 3);
 			d.SetBufferSize (width, 3);
 
 
 			// Default - Center
 			// Default - Center
@@ -405,7 +405,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 
 
@@ -423,8 +423,8 @@ namespace Terminal.Gui.Views {
 			//                         12345                          123456
 			//                         12345                          123456
 			var buttonRow = $"{d.VLine}     {btn1} {btn2} {btn3} {btn4}      {d.VLine}";
 			var buttonRow = $"{d.VLine}     {btn1} {btn2} {btn3} {btn4}      {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
 			// Default - Center
 			// Default - Center
@@ -460,14 +460,14 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 
 
 			var buttonRow = $"{d.VLine}        {d.VLine}";
 			var buttonRow = $"{d.VLine}        {d.VLine}";
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
 			(runstate, var _) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, null);
 			(runstate, var _) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, null);
@@ -482,15 +482,15 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			var btnText = "ok";
 			var btnText = "ok";
 			var buttonRow = $"{d.VLine}   {d.LeftBracket} {btnText} {d.RightBracket}   {d.VLine}";
 			var buttonRow = $"{d.VLine}   {d.LeftBracket} {btnText} {d.RightBracket}   {d.VLine}";
 
 
 			var width = buttonRow.Length;
 			var width = buttonRow.Length;
-			var topRow = $"┌ {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}┐";
-			var bottomRow = $"└{new String (d.HLine.ToString () [0], width - 2)}┘";
+			var topRow = $"┌ {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}┐";
+			var bottomRow = $"└{new string (d.HLine.ToString () [0], width - 2)}┘";
 			d.SetBufferSize (buttonRow.Length, 3);
 			d.SetBufferSize (buttonRow.Length, 3);
 
 
 			(runstate, var _) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, new Button (btnText));
 			(runstate, var _) = RunButtonTestDialog (title, width, Dialog.ButtonAlignments.Center, new Button (btnText));
@@ -504,7 +504,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			Application.RunState runstate = null;
 			Application.RunState runstate = null;
 
 
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			var btn1Text = "yes";
 			var btn1Text = "yes";
@@ -516,8 +516,8 @@ namespace Terminal.Gui.Views {
 			var width = $@"{d.VLine} {btn1} {btn2} {d.VLine}".Length;
 			var width = $@"{d.VLine} {btn1} {btn2} {d.VLine}".Length;
 			d.SetBufferSize (width, 3);
 			d.SetBufferSize (width, 3);
 
 
-			var topRow = $"{d.ULCorner} {title} {new String (d.HLine.ToString () [0], width - title.Length - 4)}{d.URCorner}";
-			var bottomRow = $"{d.LLCorner}{new String (d.HLine.ToString () [0], width - 2)}{d.LRCorner}";
+			var topRow = $"{d.ULCorner} {title} {new string (d.HLine.ToString () [0], width - title.Length - 4)}{d.URCorner}";
+			var bottomRow = $"{d.LLCorner}{new string (d.HLine.ToString () [0], width - 2)}{d.LRCorner}";
 
 
 			// Default (center)
 			// Default (center)
 			var dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Center };
 			var dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Center };
@@ -550,7 +550,7 @@ namespace Terminal.Gui.Views {
 			// Right
 			// Right
 			dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Right };
 			dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Right };
 			runstate = Application.Begin (dlg);
 			runstate = Application.Begin (dlg);
-			buttonRow = $"{d.VLine}{new String (' ', width - btn1.Length - 2)}{btn1}{d.VLine}";
+			buttonRow = $"{d.VLine}{new string (' ', width - btn1.Length - 2)}{btn1}{d.VLine}";
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 
 
 			// Now add a second button
 			// Now add a second button
@@ -564,7 +564,7 @@ namespace Terminal.Gui.Views {
 			// Left
 			// Left
 			dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Left };
 			dlg = new Dialog (title, width, 3, new Button (btn1Text)) { ButtonAlignment = Dialog.ButtonAlignments.Left };
 			runstate = Application.Begin (dlg);
 			runstate = Application.Begin (dlg);
-			buttonRow = $"{d.VLine}{btn1}{new String (' ', width - btn1.Length - 2)}{d.VLine}";
+			buttonRow = $"{d.VLine}{btn1}{new string (' ', width - btn1.Length - 2)}{d.VLine}";
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 
 
 			// Now add a second button
 			// Now add a second button
@@ -575,5 +575,16 @@ namespace Terminal.Gui.Views {
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 			TestHelpers.AssertDriverContentsWithFrameAre ($"{topRow}\n{buttonRow}\n{bottomRow}", output);
 			Application.End (runstate);
 			Application.End (runstate);
 		}
 		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void FileDialog_FileSystemWatcher ()
+		{
+			for (int i = 0; i < 8; i++) {
+				var fd = new FileDialog ();
+				fd.Ready += () => Application.RequestStop ();
+				Application.Run (fd);
+			}
+		}
 	}
 	}
 }
 }

+ 22 - 40
UnitTests/MdiTests.cs → UnitTests/TopLevels/MdiTests.cs

@@ -3,12 +3,13 @@ using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TopLevelTests {
 	public class MdiTests {
 	public class MdiTests {
 		public MdiTests ()
 		public MdiTests ()
 		{
 		{
@@ -22,7 +23,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Dispose_Toplevel_IsMdiContainer_False_With_Begin_End ()
 		public void Dispose_Toplevel_IsMdiContainer_False_With_Begin_End ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = new Toplevel ();
 			var top = new Toplevel ();
 			var rs = Application.Begin (top);
 			var rs = Application.Begin (top);
@@ -30,25 +31,28 @@ namespace Terminal.Gui.Core {
 
 
 			Application.Shutdown ();
 			Application.Shutdown ();
 
 
+#if DEBUG_IDISPOSABLE
 			Assert.Equal (2, Responder.Instances.Count);
 			Assert.Equal (2, Responder.Instances.Count);
 			Assert.True (Responder.Instances [0].WasDisposed);
 			Assert.True (Responder.Instances [0].WasDisposed);
 			Assert.True (Responder.Instances [1].WasDisposed);
 			Assert.True (Responder.Instances [1].WasDisposed);
+#endif
 		}
 		}
 
 
 		[Fact]
 		[Fact]
 		public void Dispose_Toplevel_IsMdiContainer_True_With_Begin ()
 		public void Dispose_Toplevel_IsMdiContainer_True_With_Begin ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var mdi = new Toplevel { IsMdiContainer = true };
 			var mdi = new Toplevel { IsMdiContainer = true };
 			var rs = Application.Begin (mdi);
 			var rs = Application.Begin (mdi);
 			Application.End (rs);
 			Application.End (rs);
 
 
 			Application.Shutdown ();
 			Application.Shutdown ();
-
+#if DEBUG_IDISPOSABLE
 			Assert.Equal (2, Responder.Instances.Count);
 			Assert.Equal (2, Responder.Instances.Count);
 			Assert.True (Responder.Instances [0].WasDisposed);
 			Assert.True (Responder.Instances [0].WasDisposed);
 			Assert.True (Responder.Instances [1].WasDisposed);
 			Assert.True (Responder.Instances [1].WasDisposed);
+#endif
 		}
 		}
 
 
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
@@ -91,17 +95,11 @@ namespace Terminal.Gui.Core {
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
 				Assert.Null (Application.MdiChildes);
 				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);
-				}
+				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);
 				Application.RequestStop (top1);
 				iterations--;
 				iterations--;
 			};
 			};
@@ -168,9 +166,7 @@ namespace Terminal.Gui.Core {
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
-					for (int i = 0; i < iterations; i++) {
-						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
-					}
+					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -228,9 +224,7 @@ namespace Terminal.Gui.Core {
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
-					for (int i = 0; i < iterations; i++) {
-						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
-					}
+					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -289,9 +283,7 @@ namespace Terminal.Gui.Core {
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
-					for (int i = 0; i < iterations; i++) {
-						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
-					}
+					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -389,9 +381,7 @@ namespace Terminal.Gui.Core {
 					Assert.False (Application.Current.Running);
 					Assert.False (Application.Current.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
-					for (int i = 0; i < iterations; i++) {
-						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
-					}
+					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -458,10 +448,8 @@ namespace Terminal.Gui.Core {
 					Assert.True (c4.Running);
 					Assert.True (c4.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
-					for (int i = 0; i < iterations; i++) {
-						Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
+					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
 							Application.MdiChildes [i].Id);
 							Application.MdiChildes [i].Id);
-					}
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -583,9 +571,7 @@ namespace Terminal.Gui.Core {
 					};
 					};
 
 
 					stage.Closed += (_) => {
 					stage.Closed += (_) => {
-						if (iterations == 11) {
-							allStageClosed = true;
-						}
+						if (iterations == 11) 							allStageClosed = true;
 						Assert.Equal (iterations, Application.MdiChildes.Count);
 						Assert.Equal (iterations, Application.MdiChildes.Count);
 						if (running) {
 						if (running) {
 							stageCompleted = true;
 							stageCompleted = true;
@@ -607,16 +593,12 @@ namespace Terminal.Gui.Core {
 					running = false;
 					running = false;
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 
 
-				} else if (!mdiRequestStop && running && !allStageClosed) {
-					Assert.Equal (iterations, Application.MdiChildes.Count);
-
-				} else if (!mdiRequestStop && !running && allStageClosed) {
+				} else if (!mdiRequestStop && running && !allStageClosed) 					Assert.Equal (iterations, Application.MdiChildes.Count);
+else if (!mdiRequestStop && !running && allStageClosed) {
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					Assert.Equal (iterations, Application.MdiChildes.Count);
 					mdiRequestStop = true;
 					mdiRequestStop = true;
 					mdi.RequestStop ();
 					mdi.RequestStop ();
-				} else {
-					Assert.Empty (Application.MdiChildes);
-				}
+				} else 					Assert.Empty (Application.MdiChildes);
 			};
 			};
 
 
 			Application.Run (mdi);
 			Application.Run (mdi);

+ 3 - 2
UnitTests/MessageBoxTests.cs → UnitTests/TopLevels/MessageBoxTests.cs

@@ -2,8 +2,9 @@
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using System.Text;
 using System.Text;
+using Terminal.Gui;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.TopLevelTests {
 
 
 	public class MessageBoxTests {
 	public class MessageBoxTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -54,7 +55,7 @@ namespace Terminal.Gui.Views {
 				iterations++;
 				iterations++;
 
 
 				if (iterations == 0) {
 				if (iterations == 0) {
-					StringBuilder aboutMessage = new StringBuilder ();
+					var aboutMessage = new StringBuilder ();
 					aboutMessage.AppendLine (@"A comprehensive sample library for");
 					aboutMessage.AppendLine (@"A comprehensive sample library for");
 					aboutMessage.AppendLine (@"");
 					aboutMessage.AppendLine (@"");
 					aboutMessage.AppendLine (@"  _______                  _             _   _____       _  ");
 					aboutMessage.AppendLine (@"  _______                  _             _   _____       _  ");

+ 22 - 15
UnitTests/ToplevelTests.cs → UnitTests/TopLevels/ToplevelTests.cs

@@ -1,8 +1,9 @@
 using System;
 using System;
+using Terminal.Gui;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TopLevelTests {
 	public class ToplevelTests {
 	public class ToplevelTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -596,7 +597,7 @@ namespace Terminal.Gui.Core {
 
 
 			var win = new Window ();
 			var win = new Window ();
 			win.Add (view);
 			win.Add (view);
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			var top = Application.Top;
 			var top = Application.Top;
 			top.Add (win);
 			top.Add (win);
 
 
@@ -663,7 +664,7 @@ namespace Terminal.Gui.Core {
 		[AutoInitShutdown]
 		[AutoInitShutdown]
 		public void FileDialog_FileSystemWatcher ()
 		public void FileDialog_FileSystemWatcher ()
 		{
 		{
-			for (int i = 0; i < 256; i++) {
+			for (int i = 0; i < 8; i++) {
 				var fd = new FileDialog ();
 				var fd = new FileDialog ();
 				fd.Ready += () => Application.RequestStop ();
 				fd.Ready += () => Application.RequestStop ();
 				Application.Run (fd);
 				Application.Run (fd);
@@ -695,8 +696,7 @@ namespace Terminal.Gui.Core {
 					((FakeDriver)Application.Driver).SetBufferSize (40, 15);
 					((FakeDriver)Application.Driver).SetBufferSize (40, 15);
 					MessageBox.Query ("About", "Hello Word", "Ok");
 					MessageBox.Query ("About", "Hello Word", "Ok");
 
 
-				} else if (iterations == 1) {
-					TestHelpers.AssertDriverContentsWithFrameAre (@"
+				} else if (iterations == 1) 					TestHelpers.AssertDriverContentsWithFrameAre (@"
  File                                   
  File                                   
 ┌ Window ──────────────────────────────┐
 ┌ Window ──────────────────────────────┐
 │                                      │
 │                                      │
@@ -712,8 +712,7 @@ namespace Terminal.Gui.Core {
 │                                      │
 │                                      │
 └──────────────────────────────────────┘
 └──────────────────────────────────────┘
  CTRL-N New                             ", output);
  CTRL-N New                             ", output);
-
-				} else if (iterations == 2) {
+else if (iterations == 2) {
 					Assert.Null (Application.MouseGrabView);
 					Assert.Null (Application.MouseGrabView);
 					// Grab the mouse
 					// Grab the mouse
 					ReflectionTools.InvokePrivate (
 					ReflectionTools.InvokePrivate (
@@ -816,11 +815,8 @@ namespace Terminal.Gui.Core {
 
 
 					Assert.Null (Application.MouseGrabView);
 					Assert.Null (Application.MouseGrabView);
 
 
-				} else if (iterations == 8) {
-					Application.RequestStop ();
-				} else if (iterations == 9) {
-					Application.RequestStop ();
-				}
+				} else if (iterations == 8) 					Application.RequestStop ();
+else if (iterations == 9) 					Application.RequestStop ();
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();
@@ -960,12 +956,23 @@ namespace Terminal.Gui.Core {
 
 
 					Assert.Null (Application.MouseGrabView);
 					Assert.Null (Application.MouseGrabView);
 
 
-				} else if (iterations == 8) {
-					Application.RequestStop ();
-				}
+				} else if (iterations == 8) 					Application.RequestStop ();
 			};
 			};
 
 
 			Application.Run ();
 			Application.Run ();
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void EnsureVisibleBounds_With_Border_Null_Not_Throws ()
+		{
+			var top = new Toplevel ();
+			Application.Begin (top);
+
+			var exception = Record.Exception (() => ((FakeDriver)Application.Driver).SetBufferSize (0, 10));
+			Assert.Null (exception);
+
+			exception = Record.Exception (() => ((FakeDriver)Application.Driver).SetBufferSize (10, 0));
+			Assert.Null (exception);
+		}
 	}
 	}
 }
 }

+ 8 - 7
UnitTests/WindowTests.cs → UnitTests/TopLevels/WindowTests.cs

@@ -1,13 +1,14 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
-using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
+//using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 using NStack;
 using NStack;
+using Terminal.Gui;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TopLevelTests {
 	public class WindowTests {
 	public class WindowTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -22,7 +23,7 @@ namespace Terminal.Gui.Core {
 			// Parameterless
 			// Parameterless
 			var r = new Window ();
 			var r = new Window ();
 			Assert.NotNull (r);
 			Assert.NotNull (r);
-			Assert.Equal(ustring.Empty, r.Title);
+			Assert.Equal (ustring.Empty, r.Title);
 			Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
 			Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
 			Assert.Equal ("Window()({X=0,Y=0,Width=0,Height=0})", r.ToString ());
 			Assert.Equal ("Window()({X=0,Y=0,Width=0,Height=0})", r.ToString ());
 			Assert.True (r.CanFocus);
 			Assert.True (r.CanFocus);
@@ -116,13 +117,13 @@ namespace Terminal.Gui.Core {
 			r.Title = expectedDuring = expectedAfter = "title";
 			r.Title = expectedDuring = expectedAfter = "title";
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 
 
-			expectedOld = r.Title.ToString();
+			expectedOld = r.Title.ToString ();
 			r.Title = expectedDuring = expectedAfter = "a different title";
 			r.Title = expectedDuring = expectedAfter = "a different title";
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 
 
 			// Now setup cancelling the change and change it back to "title"
 			// Now setup cancelling the change and change it back to "title"
 			cancel = true;
 			cancel = true;
-			expectedOld = r.Title.ToString();
+			expectedOld = r.Title.ToString ();
 			r.Title = expectedDuring = "title";
 			r.Title = expectedDuring = "title";
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 			Assert.Equal (expectedAfter, r.Title.ToString ());
 			r.Dispose ();
 			r.Dispose ();
@@ -154,7 +155,7 @@ namespace Terminal.Gui.Core {
 			r.Dispose ();
 			r.Dispose ();
 		}
 		}
 
 
-		[Fact,AutoInitShutdown]
+		[Fact, AutoInitShutdown]
 		public void MenuBar_And_StatusBar_Inside_Window ()
 		public void MenuBar_And_StatusBar_Inside_Window ()
 		{
 		{
 			var menu = new MenuBar (new MenuBarItem [] {
 			var menu = new MenuBar (new MenuBarItem [] {
@@ -175,7 +176,7 @@ namespace Terminal.Gui.Core {
 
 
 			var fv = new FrameView ("Frame View") {
 			var fv = new FrameView ("Frame View") {
 				Y = 1,
 				Y = 1,
-				Width = Dim.Fill(),
+				Width = Dim.Fill (),
 				Height = Dim.Fill (1)
 				Height = Dim.Fill (1)
 			};
 			};
 			var win = new Window ();
 			var win = new Window ();

+ 21 - 21
UnitTests/WizardTests.cs → UnitTests/TopLevels/WizardTests.cs

@@ -9,7 +9,7 @@ using System.Globalization;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using NStack;
 using NStack;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.TopLevelTests {
 
 
 	public class WizardTests {
 	public class WizardTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -92,7 +92,7 @@ namespace Terminal.Gui.Views {
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void DefaultConstructor_SizedProperly ()
 		public void DefaultConstructor_SizedProperly ()
 		{
 		{
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var wizard = new Wizard ();
 			var wizard = new Wizard ();
 			Assert.NotEqual (0, wizard.Width);
 			Assert.NotEqual (0, wizard.Width);
@@ -104,7 +104,7 @@ namespace Terminal.Gui.Views {
 		// and that the title is correct
 		// and that the title is correct
 		public void ZeroStepWizard_Shows ()
 		public void ZeroStepWizard_Shows ()
 		{
 		{
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			var stepTitle = "";
 			var stepTitle = "";
@@ -118,12 +118,12 @@ namespace Terminal.Gui.Views {
 			var btnNextText = "Finish";
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
 
-			var topRow = $"{d.ULDCorner} {title}{stepTitle} {new String (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
-			var row2 = $"{d.VDLine}{new String (' ', width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDCorner} {title}{stepTitle} {new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
+			var row2 = $"{d.VDLine}{new string (' ', width - 2)}{d.VDLine}";
 			var row3 = row2;
 			var row3 = row2;
-			var separatorRow = $"{d.VDLine}{new String (' ', width - 2)}{d.VDLine}";
-			var buttonRow = $"{d.VDLine}{btnBack}{new String (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new String (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var separatorRow = $"{d.VDLine}{new string (' ', width - 2)}{d.VDLine}";
+			var buttonRow = $"{d.VDLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
+			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
 
 
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			Application.End (Application.Begin (wizard));
 			Application.End (Application.Begin (wizard));
@@ -135,7 +135,7 @@ namespace Terminal.Gui.Views {
 		// and that the title is correct
 		// and that the title is correct
 		public void OneStepWizard_Shows ()
 		public void OneStepWizard_Shows ()
 		{
 		{
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			var stepTitle = "ABCD";
 			var stepTitle = "ABCD";
@@ -149,13 +149,13 @@ namespace Terminal.Gui.Views {
 			var btnNextText = "Finish"; // "Next";
 			var btnNextText = "Finish"; // "Next";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
 
-			var topRow = $"{d.ULDCorner} {title} - {stepTitle} {new String (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 7)}{d.URDCorner}";
-			var row2 = $"{d.VDLine}{new String (' ', width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDCorner} {title} - {stepTitle} {new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 7)}{d.URDCorner}";
+			var row2 = $"{d.VDLine}{new string (' ', width - 2)}{d.VDLine}";
 			var row3 = row2;
 			var row3 = row2;
 			var row4 = row3;
 			var row4 = row3;
-			var separatorRow = $"{d.VDLine}{new String (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
-			var buttonRow = $"{d.VDLine}{btnBack}{new String (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new String (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var separatorRow = $"{d.VDLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
+			var buttonRow = $"{d.VDLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
+			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
 
 
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep (stepTitle));
 			wizard.AddStep (new Wizard.WizardStep (stepTitle));
@@ -207,7 +207,7 @@ namespace Terminal.Gui.Views {
 		// this test is needed because Wizard overrides Dialog's title behavior ("Title - StepTitle")
 		// this test is needed because Wizard overrides Dialog's title behavior ("Title - StepTitle")
 		public void Setting_Title_Works ()
 		public void Setting_Title_Works ()
 		{
 		{
-			var d = ((FakeDriver)Application.Driver);
+			var d = (FakeDriver)Application.Driver;
 
 
 			var title = "1234";
 			var title = "1234";
 			var stepTitle = " - ABCD";
 			var stepTitle = " - ABCD";
@@ -219,13 +219,13 @@ namespace Terminal.Gui.Views {
 			var btnNextText = "Finish";
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
 
-			var topRow = $"{d.ULDCorner} {title}{stepTitle} {new String (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
-			var separatorRow = $"{d.VDLine}{new String (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDCorner} {title}{stepTitle} {new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
+			var separatorRow = $"{d.VDLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
 
 
 			// Once this is fixed, revert to commented out line: https://github.com/gui-cs/Terminal.Gui/issues/1791
 			// Once this is fixed, revert to commented out line: https://github.com/gui-cs/Terminal.Gui/issues/1791
-			var buttonRow = $"{d.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
+			var buttonRow = $"{d.VDLine}{new string (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
 			//var buttonRow = $"{d.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
 			//var buttonRow = $"{d.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new String (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
 
 
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			var wizard = new Wizard (title) { Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep ("ABCD"));
 			wizard.AddStep (new Wizard.WizardStep ("ABCD"));
@@ -560,13 +560,13 @@ namespace Terminal.Gui.Views {
 			runstate = Application.Begin (wizard);
 			runstate = Application.Begin (wizard);
 			Application.RunMainLoopIteration (ref runstate, true, ref firstIteration);
 			Application.RunMainLoopIteration (ref runstate, true, ref firstIteration);
 
 
-			Assert.Equal (step1.Title.ToString(), wizard.CurrentStep.Title.ToString());
+			Assert.Equal (step1.Title.ToString (), wizard.CurrentStep.Title.ToString ());
 			wizard.NextFinishButton.OnClicked ();
 			wizard.NextFinishButton.OnClicked ();
 			Assert.False (finishedFired);
 			Assert.False (finishedFired);
 			Assert.False (closedFired);
 			Assert.False (closedFired);
 
 
 			Assert.Equal (step2.Title.ToString (), wizard.CurrentStep.Title.ToString ());
 			Assert.Equal (step2.Title.ToString (), wizard.CurrentStep.Title.ToString ());
-			Assert.Equal (wizard.GetLastStep().Title.ToString(), wizard.CurrentStep.Title.ToString ());
+			Assert.Equal (wizard.GetLastStep ().Title.ToString (), wizard.CurrentStep.Title.ToString ());
 			wizard.NextFinishButton.OnClicked ();
 			wizard.NextFinishButton.OnClicked ();
 			Application.End (runstate);
 			Application.End (runstate);
 			Assert.True (finishedFired);
 			Assert.True (finishedFired);

+ 14 - 19
UnitTests/DimTests.cs → UnitTests/Types/DimTests.cs

@@ -6,14 +6,13 @@ using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using Terminal.Gui;
 using Terminal.Gui;
-using Terminal.Gui.Views;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TypeTests {
 	public class DimTests {
 	public class DimTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -22,7 +21,7 @@ namespace Terminal.Gui.Core {
 			this.output = output;
 			this.output = output;
 			Console.OutputEncoding = System.Text.Encoding.Default;
 			Console.OutputEncoding = System.Text.Encoding.Default;
 			// Change current culture
 			// Change current culture
-			CultureInfo culture = CultureInfo.CreateSpecificCulture ("en-US");
+			var culture = CultureInfo.CreateSpecificCulture ("en-US");
 			Thread.CurrentThread.CurrentCulture = culture;
 			Thread.CurrentThread.CurrentCulture = culture;
 			Thread.CurrentThread.CurrentUICulture = culture;
 			Thread.CurrentThread.CurrentUICulture = culture;
 		}
 		}
@@ -252,7 +251,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void ForceValidatePosDim_True_Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type ()
 		public void ForceValidatePosDim_True_Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -292,7 +291,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
 		public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -313,7 +312,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
 		public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -346,7 +345,7 @@ namespace Terminal.Gui.Core {
 		{
 		{
 			// Testing with the Button because it properly handles the Dim class.
 			// Testing with the Button because it properly handles the Dim class.
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -541,7 +540,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void DimCombine_Do_Not_Throws ()
 		public void DimCombine_Do_Not_Throws ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -588,7 +587,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void PosCombine_Will_Throws ()
 		public void PosCombine_Will_Throws ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -622,7 +621,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Add_Operator ()
 		public void Dim_Add_Operator ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -646,9 +645,7 @@ namespace Terminal.Gui.Core {
 			};
 			};
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
-				while (count < 20) {
-					field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
-				}
+				while (count < 20) 					field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
 
 
 				Application.RequestStop ();
 				Application.RequestStop ();
 			};
 			};
@@ -989,7 +986,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Add_Operator_With_Text ()
 		public void Dim_Add_Operator_With_Text ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -1056,7 +1053,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Subtract_Operator ()
 		public void Dim_Subtract_Operator ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -1091,9 +1088,7 @@ namespace Terminal.Gui.Core {
 			};
 			};
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
-				while (count > 0) {
-					field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
-				}
+				while (count > 0) 					field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
 
 
 				Application.RequestStop ();
 				Application.RequestStop ();
 			};
 			};
@@ -1116,7 +1111,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Subtract_Operator_With_Text ()
 		public void Dim_Subtract_Operator_With_Text ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 

+ 1 - 1
UnitTests/PointTests.cs → UnitTests/Types/PointTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Types {
+namespace Terminal.Gui.TypeTests {
 	public class PointTests {
 	public class PointTests {
 		[Fact]
 		[Fact]
 		public void Point_New ()
 		public void Point_New ()

+ 9 - 10
UnitTests/PosTests.cs → UnitTests/Types/PosTests.cs

@@ -5,14 +5,13 @@ using System.Data;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using Terminal.Gui;
 using Terminal.Gui;
-using Terminal.Gui.Views;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.TypeTests {
 	public class PosTests {
 	public class PosTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -555,7 +554,7 @@ namespace Terminal.Gui.Core {
 			// Setup Fake driver
 			// Setup Fake driver
 			(Window win, Button button) setup ()
 			(Window win, Button button) setup ()
 			{
 			{
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 				Application.Iteration = () => {
 				Application.Iteration = () => {
 					Application.RequestStop ();
 					Application.RequestStop ();
 				};
 				};
@@ -700,7 +699,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void ForceValidatePosDim_True_Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
 		public void ForceValidatePosDim_True_Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -733,7 +732,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
 		public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -755,7 +754,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
 		public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -788,7 +787,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void PosCombine_Do_Not_Throws ()
 		public void PosCombine_Do_Not_Throws ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -835,7 +834,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void PosCombine_Will_Throws ()
 		public void PosCombine_Will_Throws ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -868,7 +867,7 @@ namespace Terminal.Gui.Core {
 		public void Pos_Add_Operator ()
 		public void Pos_Add_Operator ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 
@@ -917,7 +916,7 @@ namespace Terminal.Gui.Core {
 		public void Pos_Subtract_Operator ()
 		public void Pos_Subtract_Operator ()
 		{
 		{
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var top = Application.Top;
 			var top = Application.Top;
 
 

+ 1 - 1
UnitTests/RectTests.cs → UnitTests/Types/RectTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Types {
+namespace Terminal.Gui.TypeTests {
 	public class RectTests {
 	public class RectTests {
 		[Fact]
 		[Fact]
 		public void Rect_New ()
 		public void Rect_New ()

+ 1 - 1
UnitTests/SizeTests.cs → UnitTests/Types/SizeTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Types {
+namespace Terminal.Gui.TypeTests {
 	public class SizeTests {
 	public class SizeTests {
 		[Fact]
 		[Fact]
 		public void Size_New ()
 		public void Size_New ()

+ 566 - 0
UnitTests/UICatalog/ScenarioTests.cs

@@ -0,0 +1,566 @@
+using NStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Terminal.Gui;
+using UICatalog;
+using Xunit;
+using Xunit.Abstractions;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace UICatalog.Tests {
+	public class ScenarioTests {
+		readonly ITestOutputHelper output;
+
+		public ScenarioTests (ITestOutputHelper output)
+		{
+#if DEBUG_IDISPOSABLE
+			Responder.Instances.Clear ();
+#endif
+			this.output = output;
+		}
+
+		int CreateInput (string input)
+		{
+			// Put a control-q in at the end
+			FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true));
+			foreach (var c in input.Reverse ()) {
+				if (char.IsLetter (c)) {
+					FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (char.ToLower (c), (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false));
+				} else {
+					FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false));
+				}
+			}
+			return FakeConsole.MockKeyPresses.Count;
+		}
+
+
+		/// <summary>
+		/// <para>
+		/// This runs through all Scenarios defined in UI Catalog, calling Init, Setup, and Run.
+		/// </para>
+		/// <para>
+		/// Should find any Scenarios which crash on load or do not respond to <see cref="Application.RequestStop()"/>.
+		/// </para>
+		/// </summary>
+		[Fact]
+		public void Run_All_Scenarios ()
+		{
+			List<Scenario> scenarios = Scenario.GetScenarios ();
+			Assert.NotEmpty (scenarios);
+
+			foreach (var scenario in scenarios) {
+
+				output.WriteLine ($"Running Scenario '{scenario}'");
+
+				Func<MainLoop, bool> closeCallback = (MainLoop loop) => {
+					Application.RequestStop ();
+					return false;
+				};
+
+				Application.Init (new FakeDriver ());
+
+				// Close after a short period of time
+				var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), closeCallback);
+
+				scenario.Init (Colors.Base);
+				scenario.Setup ();
+				scenario.Run ();
+				Application.Shutdown ();
+#if DEBUG_IDISPOSABLE
+				foreach (var inst in Responder.Instances) {
+					Assert.True (inst.WasDisposed);
+				}
+				Responder.Instances.Clear ();
+#endif
+			}
+#if DEBUG_IDISPOSABLE
+			foreach (var inst in Responder.Instances) {
+				Assert.True (inst.WasDisposed);
+			}
+			Responder.Instances.Clear ();
+#endif
+		}
+
+		[Fact]
+		public void Run_Generic ()
+		{
+			List<Scenario> scenarios = Scenario.GetScenarios ();
+			Assert.NotEmpty (scenarios);
+
+			var item = scenarios.FindIndex (s => s.GetName ().Equals ("Generic", StringComparison.OrdinalIgnoreCase));
+			var generic = scenarios [item];
+			// Setup some fake keypresses 
+			// Passing empty string will cause just a ctrl-q to be fired
+			int stackSize = CreateInput ("");
+
+			Application.Init (new FakeDriver ());
+
+			int iterations = 0;
+			Application.Iteration = () => {
+				iterations++;
+				// Stop if we run out of control...
+				if (iterations == 10) {
+					Application.RequestStop ();
+				}
+			};
+
+			var ms = 1000;
+			var abortCount = 0;
+			Func<MainLoop, bool> abortCallback = (MainLoop loop) => {
+				abortCount++;
+				Application.RequestStop ();
+				return false;
+			};
+			var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (ms), abortCallback);
+
+			Application.Top.KeyPress += (View.KeyEventEventArgs args) => {
+				Assert.Equal (Key.CtrlMask | Key.Q, args.KeyEvent.Key);
+			};
+
+			generic.Init (Colors.Base);
+			generic.Setup ();
+			// 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);
+			generic.Run ();
+
+			//Application.End (rs);
+
+			Assert.Equal (0, abortCount);
+			// # of key up events should match # of iterations
+			Assert.Equal (1, iterations);
+			// 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);
+			}
+			Responder.Instances.Clear ();
+#endif
+		}
+
+		[Fact]
+		public void Run_All_Views_Tester_Scenario ()
+		{
+			Window _leftPane;
+			ListView _classListView;
+			FrameView _hostPane;
+
+			Dictionary<string, Type> _viewClasses;
+			View _curView = null;
+
+			// Settings
+			FrameView _settingsPane;
+			CheckBox _computedCheckBox;
+			FrameView _locationFrame;
+			RadioGroup _xRadioGroup;
+			TextField _xText;
+			int _xVal = 0;
+			RadioGroup _yRadioGroup;
+			TextField _yText;
+			int _yVal = 0;
+
+			FrameView _sizeFrame;
+			RadioGroup _wRadioGroup;
+			TextField _wText;
+			int _wVal = 0;
+			RadioGroup _hRadioGroup;
+			TextField _hText;
+			int _hVal = 0;
+			List<string> posNames = new List<String> { "Factor", "AnchorEnd", "Center", "Absolute" };
+			List<string> dimNames = new List<String> { "Factor", "Fill", "Absolute" };
+
+
+			Application.Init (new FakeDriver ());
+
+			var Top = Application.Top;
+
+			_viewClasses = GetAllViewClassesCollection ()
+				.OrderBy (t => t.Name)
+				.Select (t => new KeyValuePair<string, Type> (t.Name, t))
+				.ToDictionary (t => t.Key, t => t.Value);
+
+			_leftPane = new Window ("Classes") {
+				X = 0,
+				Y = 0,
+				Width = 15,
+				Height = Dim.Fill (1), // for status bar
+				CanFocus = false,
+				ColorScheme = Colors.TopLevel,
+			};
+
+			_classListView = new ListView (_viewClasses.Keys.ToList ()) {
+				X = 0,
+				Y = 0,
+				Width = Dim.Fill (0),
+				Height = Dim.Fill (0),
+				AllowsMarking = false,
+				ColorScheme = Colors.TopLevel,
+			};
+			_leftPane.Add (_classListView);
+
+			_settingsPane = new FrameView ("Settings") {
+				X = Pos.Right (_leftPane),
+				Y = 0, // for menu
+				Width = Dim.Fill (),
+				Height = 10,
+				CanFocus = false,
+				ColorScheme = Colors.TopLevel,
+			};
+			_computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 };
+			_settingsPane.Add (_computedCheckBox);
+
+			var radioItems = new ustring [] { "Percent(x)", "AnchorEnd(x)", "Center", "At(x)" };
+			_locationFrame = new FrameView ("Location (Pos)") {
+				X = Pos.Left (_computedCheckBox),
+				Y = Pos.Bottom (_computedCheckBox),
+				Height = 3 + radioItems.Length,
+				Width = 36,
+			};
+			_settingsPane.Add (_locationFrame);
+
+			var label = new Label ("x:") { X = 0, Y = 0 };
+			_locationFrame.Add (label);
+			_xRadioGroup = new RadioGroup (radioItems) {
+				X = 0,
+				Y = Pos.Bottom (label),
+			};
+			_xText = new TextField ($"{_xVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+			_locationFrame.Add (_xText);
+
+			_locationFrame.Add (_xRadioGroup);
+
+			radioItems = new ustring [] { "Percent(y)", "AnchorEnd(y)", "Center", "At(y)" };
+			label = new Label ("y:") { X = Pos.Right (_xRadioGroup) + 1, Y = 0 };
+			_locationFrame.Add (label);
+			_yText = new TextField ($"{_yVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+			_locationFrame.Add (_yText);
+			_yRadioGroup = new RadioGroup (radioItems) {
+				X = Pos.X (label),
+				Y = Pos.Bottom (label),
+			};
+			_locationFrame.Add (_yRadioGroup);
+
+			_sizeFrame = new FrameView ("Size (Dim)") {
+				X = Pos.Right (_locationFrame),
+				Y = Pos.Y (_locationFrame),
+				Height = 3 + radioItems.Length,
+				Width = 40,
+			};
+
+			radioItems = new ustring [] { "Percent(width)", "Fill(width)", "Sized(width)" };
+			label = new Label ("width:") { X = 0, Y = 0 };
+			_sizeFrame.Add (label);
+			_wRadioGroup = new RadioGroup (radioItems) {
+				X = 0,
+				Y = Pos.Bottom (label),
+			};
+			_wText = new TextField ($"{_wVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+			_sizeFrame.Add (_wText);
+			_sizeFrame.Add (_wRadioGroup);
+
+			radioItems = new ustring [] { "Percent(height)", "Fill(height)", "Sized(height)" };
+			label = new Label ("height:") { X = Pos.Right (_wRadioGroup) + 1, Y = 0 };
+			_sizeFrame.Add (label);
+			_hText = new TextField ($"{_hVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+			_sizeFrame.Add (_hText);
+
+			_hRadioGroup = new RadioGroup (radioItems) {
+				X = Pos.X (label),
+				Y = Pos.Bottom (label),
+			};
+			_sizeFrame.Add (_hRadioGroup);
+
+			_settingsPane.Add (_sizeFrame);
+
+			_hostPane = new FrameView ("") {
+				X = Pos.Right (_leftPane),
+				Y = Pos.Bottom (_settingsPane),
+				Width = Dim.Fill (),
+				Height = Dim.Fill (1), // + 1 for status bar
+				ColorScheme = Colors.Dialog,
+			};
+
+			_classListView.OpenSelectedItem += (a) => {
+				_settingsPane.SetFocus ();
+			};
+			_classListView.SelectedItemChanged += (args) => {
+				ClearClass (_curView);
+				_curView = CreateClass (_viewClasses.Values.ToArray () [_classListView.SelectedItem]);
+			};
+
+			_computedCheckBox.Toggled += (previousState) => {
+				if (_curView != null) {
+					_curView.LayoutStyle = previousState ? LayoutStyle.Absolute : LayoutStyle.Computed;
+					_hostPane.LayoutSubviews ();
+				}
+			};
+
+			_xRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView);
+
+			_xText.TextChanged += (args) => {
+				try {
+					_xVal = int.Parse (_xText.Text.ToString ());
+					DimPosChanged (_curView);
+				} catch {
+
+				}
+			};
+
+			_yText.TextChanged += (args) => {
+				try {
+					_yVal = int.Parse (_yText.Text.ToString ());
+					DimPosChanged (_curView);
+				} catch {
+
+				}
+			};
+
+			_yRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView);
+
+			_wRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView);
+
+			_wText.TextChanged += (args) => {
+				try {
+					_wVal = int.Parse (_wText.Text.ToString ());
+					DimPosChanged (_curView);
+				} catch {
+
+				}
+			};
+
+			_hText.TextChanged += (args) => {
+				try {
+					_hVal = int.Parse (_hText.Text.ToString ());
+					DimPosChanged (_curView);
+				} catch {
+
+				}
+			};
+
+			_hRadioGroup.SelectedItemChanged += (selected) => DimPosChanged (_curView);
+
+			Top.Add (_leftPane, _settingsPane, _hostPane);
+
+			Top.LayoutSubviews ();
+
+			_curView = CreateClass (_viewClasses.First ().Value);
+
+			int iterations = 0;
+
+			Application.Iteration += () => {
+				iterations++;
+
+				if (iterations < _viewClasses.Count) {
+					_classListView.MoveDown ();
+					Assert.Equal (_curView.GetType ().Name,
+						_viewClasses.Values.ToArray () [_classListView.SelectedItem].Name);
+				} else {
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+
+			Assert.Equal (_viewClasses.Count, iterations);
+
+			Application.Shutdown ();
+
+
+			void DimPosChanged (View view)
+			{
+				if (view == null) {
+					return;
+				}
+
+				var layout = view.LayoutStyle;
+
+				try {
+					view.LayoutStyle = LayoutStyle.Absolute;
+
+					switch (_xRadioGroup.SelectedItem) {
+					case 0:
+						view.X = Pos.Percent (_xVal);
+						break;
+					case 1:
+						view.X = Pos.AnchorEnd (_xVal);
+						break;
+					case 2:
+						view.X = Pos.Center ();
+						break;
+					case 3:
+						view.X = Pos.At (_xVal);
+						break;
+					}
+
+					switch (_yRadioGroup.SelectedItem) {
+					case 0:
+						view.Y = Pos.Percent (_yVal);
+						break;
+					case 1:
+						view.Y = Pos.AnchorEnd (_yVal);
+						break;
+					case 2:
+						view.Y = Pos.Center ();
+						break;
+					case 3:
+						view.Y = Pos.At (_yVal);
+						break;
+					}
+
+					switch (_wRadioGroup.SelectedItem) {
+					case 0:
+						view.Width = Dim.Percent (_wVal);
+						break;
+					case 1:
+						view.Width = Dim.Fill (_wVal);
+						break;
+					case 2:
+						view.Width = Dim.Sized (_wVal);
+						break;
+					}
+
+					switch (_hRadioGroup.SelectedItem) {
+					case 0:
+						view.Height = Dim.Percent (_hVal);
+						break;
+					case 1:
+						view.Height = Dim.Fill (_hVal);
+						break;
+					case 2:
+						view.Height = Dim.Sized (_hVal);
+						break;
+					}
+				} catch (Exception e) {
+					MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+				} finally {
+					view.LayoutStyle = layout;
+				}
+				UpdateTitle (view);
+			}
+
+			void UpdateSettings (View view)
+			{
+				var x = view.X.ToString ();
+				var y = view.Y.ToString ();
+				_xRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => x.Contains (s)).First ());
+				_yRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => y.Contains (s)).First ());
+				_xText.Text = $"{view.Frame.X}";
+				_yText.Text = $"{view.Frame.Y}";
+
+				var w = view.Width.ToString ();
+				var h = view.Height.ToString ();
+				_wRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => w.Contains (s)).First ());
+				_hRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => h.Contains (s)).First ());
+				_wText.Text = $"{view.Frame.Width}";
+				_hText.Text = $"{view.Frame.Height}";
+			}
+
+			void UpdateTitle (View view)
+			{
+				_hostPane.Title = $"{view.GetType ().Name} - {view.X.ToString ()}, {view.Y.ToString ()}, {view.Width.ToString ()}, {view.Height.ToString ()}";
+			}
+
+			List<Type> GetAllViewClassesCollection ()
+			{
+				List<Type> types = new List<Type> ();
+				foreach (Type type in typeof (View).Assembly.GetTypes ()
+				 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) {
+					types.Add (type);
+				}
+				return types;
+			}
+
+			void ClearClass (View view)
+			{
+				// Remove existing class, if any
+				if (view != null) {
+					view.LayoutComplete -= LayoutCompleteHandler;
+					_hostPane.Remove (view);
+					view.Dispose ();
+					_hostPane.Clear ();
+				}
+			}
+
+			View CreateClass (Type type)
+			{
+				// If we are to create a generic Type
+				if (type.IsGenericType) {
+
+					// For each of the <T> arguments
+					List<Type> typeArguments = new List<Type> ();
+
+					// use <object>
+					foreach (var arg in type.GetGenericArguments ()) {
+						typeArguments.Add (typeof (object));
+					}
+
+					// And change what type we are instantiating from MyClass<T> to MyClass<object>
+					type = type.MakeGenericType (typeArguments.ToArray ());
+				}
+				// Instantiate view
+				var view = (View)Activator.CreateInstance (type);
+
+				//_curView.X = Pos.Center ();
+				//_curView.Y = Pos.Center ();
+				view.Width = Dim.Percent (75);
+				view.Height = Dim.Percent (75);
+
+				// Set the colorscheme to make it stand out if is null by default
+				if (view.ColorScheme == null) {
+					view.ColorScheme = Colors.Base;
+				}
+
+				// If the view supports a Text property, set it so we have something to look at
+				if (view.GetType ().GetProperty ("Text") != null) {
+					try {
+						view.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (view, new [] { ustring.Make ("Test Text") });
+					} catch (TargetInvocationException e) {
+						MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok");
+						view = null;
+					}
+				}
+
+				// If the view supports a Title property, set it so we have something to look at
+				if (view != null && view.GetType ().GetProperty ("Title") != null) {
+					view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { ustring.Make ("Test Title") });
+				}
+
+				// If the view supports a Source property, set it so we have something to look at
+				if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType ().GetProperty ("Source").PropertyType == typeof (Terminal.Gui.IListDataSource)) {
+					var source = new ListWrapper (new List<ustring> () { ustring.Make ("Test Text #1"), ustring.Make ("Test Text #2"), ustring.Make ("Test Text #3") });
+					view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
+				}
+
+				// Set Settings
+				_computedCheckBox.Checked = view.LayoutStyle == LayoutStyle.Computed;
+
+				// Add
+				_hostPane.Add (view);
+				//DimPosChanged ();
+				_hostPane.LayoutSubviews ();
+				_hostPane.Clear ();
+				_hostPane.SetNeedsDisplay ();
+				UpdateSettings (view);
+				UpdateTitle (view);
+
+				view.LayoutComplete += LayoutCompleteHandler;
+
+				return view;
+			}
+
+			void LayoutCompleteHandler (View.LayoutEventArgs args)
+			{
+				UpdateTitle (_curView);
+			}
+		}
+	}
+}

+ 4 - 1
UnitTests/UnitTests.csproj

@@ -1,6 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFramework>net6.0</TargetFramework>
+    <TargetFramework>net7.0</TargetFramework>
+    <!-- https://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types -->
+    <!-- for AutoInitShutdown attribute -->
+    <LangVersion>Preview</LangVersion>
     <IsPackable>false</IsPackable>
     <IsPackable>false</IsPackable>
     <UseDataCollector />
     <UseDataCollector />
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->

+ 3 - 3
UnitTests/AllViewsTests.cs → UnitTests/Views/AllViewsTests.cs

@@ -5,12 +5,12 @@ using System.Reflection;
 using Xunit;
 using Xunit;
 using System.IO;
 using System.IO;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class AllViewsTests {
 	public class AllViewsTests {
 		[Fact]
 		[Fact]
 		public void AllViews_Tests_All_Constructors ()
 		public void AllViews_Tests_All_Constructors ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			foreach (var type in GetAllViewClassesCollection ()) {
 			foreach (var type in GetAllViewClassesCollection ()) {
 				Assert.True (Constructors_FullTest (type));
 				Assert.True (Constructors_FullTest (type));
@@ -127,7 +127,7 @@ namespace Terminal.Gui.Views {
 		public void AllViews_Enter_Leave_Events ()
 		public void AllViews_Enter_Leave_Events ()
 		{
 		{
 			foreach (var type in GetAllViewClassesCollection ()) {
 			foreach (var type in GetAllViewClassesCollection ()) {
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 
 				var top = Application.Top;
 				var top = Application.Top;
 				var vType = GetTypeInitializer (type, type.GetConstructor (Array.Empty<Type> ()));
 				var vType = GetTypeInitializer (type, type.GetConstructor (Array.Empty<Type> ()));

+ 1 - 1
UnitTests/AutocompleteTests.cs → UnitTests/Views/AutocompleteTests.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 using Terminal.Gui;
 using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ViewTests {
 	public class AutocompleteTests {
 	public class AutocompleteTests {
 
 
 		[Fact]
 		[Fact]

+ 1 - 1
UnitTests/ButtonTests.cs → UnitTests/Views/ButtonTests.cs

@@ -2,7 +2,7 @@
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ButtonTests {
 	public class ButtonTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 1 - 1
UnitTests/CheckboxTests.cs → UnitTests/Views/CheckboxTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class CheckboxTests {
 	public class CheckboxTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 1 - 1
UnitTests/ColorPickerTests.cs → UnitTests/Views/ColorPickerTests.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ColorPickerTests {
 	public class ColorPickerTests {
 		[Fact]
 		[Fact]
 		public void Constructors ()
 		public void Constructors ()

+ 1 - 1
UnitTests/ComboBoxTests.cs → UnitTests/Views/ComboBoxTests.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ComboBoxTests {
 	public class ComboBoxTests {
 		ITestOutputHelper output;
 		ITestOutputHelper output;
 
 

+ 1 - 1
UnitTests/DateFieldTests.cs → UnitTests/Views/DateFieldTests.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class DateFieldTests {
 	public class DateFieldTests {
 		[Fact]
 		[Fact]
 		public void Constructors_Defaults ()
 		public void Constructors_Defaults ()

+ 1 - 1
UnitTests/FrameViewTests.cs → UnitTests/Views/FrameViewTests.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class FrameViewTests {
 	public class FrameViewTests {
 		[Fact]
 		[Fact]
 		public void Constuctors_Defaults ()
 		public void Constuctors_Defaults ()

+ 3 - 3
UnitTests/GraphViewTests.cs → UnitTests/Views/GraphViewTests.cs

@@ -11,7 +11,7 @@ using System.Text.RegularExpressions;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using Rune = System.Rune;
 using Rune = System.Rune;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 
 
 	#region Helper Classes
 	#region Helper Classes
 	class FakeHAxis : HorizontalAxis {
 	class FakeHAxis : HorizontalAxis {
@@ -58,7 +58,7 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
 			try {
 			try {
-				Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (driver);
 			} catch (InvalidOperationException) {
 			} catch (InvalidOperationException) {
 
 
 				// close it so that we don't get a thousand of these errors in a row
 				// close it so that we don't get a thousand of these errors in a row
@@ -1506,7 +1506,7 @@ namespace Terminal.Gui.Views {
 		public void LabelChangeText_RendersCorrectly (bool useFill)
 		public void LabelChangeText_RendersCorrectly (bool useFill)
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 
 
 			// create a wide window
 			// create a wide window

+ 1 - 1
UnitTests/HexViewTests.cs → UnitTests/Views/HexViewTests.cs

@@ -6,7 +6,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class HexViewTests {
 	public class HexViewTests {
 		[Fact]
 		[Fact]
 		public void Constructors_Defaults ()
 		public void Constructors_Defaults ()

+ 1 - 1
UnitTests/LineViewTests.cs → UnitTests/Views/LineViewTests.cs

@@ -1,7 +1,7 @@
 using Terminal.Gui.Graphs;
 using Terminal.Gui.Graphs;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class LineViewTests {
 	public class LineViewTests {
 
 
 		[Fact]
 		[Fact]

+ 64 - 2
UnitTests/ListViewTests.cs → UnitTests/Views/ListViewTests.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ListViewTests {
 	public class ListViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -203,7 +203,7 @@ namespace Terminal.Gui.Views {
 
 
 		[Fact]
 		[Fact]
 		[AutoInitShutdown]
 		[AutoInitShutdown]
-		public void EnsuresVisibilitySelectedItem_Top ()
+		public void EnsureSelectedItemVisible_Top ()
 		{
 		{
 			var source = new List<string> () { "First", "Second" };
 			var source = new List<string> () { "First", "Second" };
 			ListView lv = new ListView (source) { Width = Dim.Fill (), Height = 1 };
 			ListView lv = new ListView (source) { Width = Dim.Fill (), Height = 1 };
@@ -451,5 +451,67 @@ namespace Terminal.Gui.Views {
 			lv.SetSourceAsync (null);
 			lv.SetSourceAsync (null);
 			Assert.NotNull (lv.Source);
 			Assert.NotNull (lv.Source);
 		}
 		}
+
+		[Fact]
+		public void ListWrapper_StartsWith ()
+		{
+			var lw = new ListWrapper (new List<string> { "One", "Two", "Three" });
+
+			Assert.Equal (1, lw.StartsWith ("t"));
+			Assert.Equal (1, lw.StartsWith ("tw"));
+			Assert.Equal (2, lw.StartsWith ("th"));
+			Assert.Equal (1, lw.StartsWith ("T"));
+			Assert.Equal (1, lw.StartsWith ("TW"));
+			Assert.Equal (2, lw.StartsWith ("TH"));
+
+			lw = new ListWrapper (new List<NStack.ustring> { "One", "Two", "Three" });
+
+			Assert.Equal (1, lw.StartsWith ("t"));
+			Assert.Equal (1, lw.StartsWith ("tw"));
+			Assert.Equal (2, lw.StartsWith ("th"));
+			Assert.Equal (1, lw.StartsWith ("T"));
+			Assert.Equal (1, lw.StartsWith ("TW"));
+			Assert.Equal (2, lw.StartsWith ("TH"));
+		}
+
+		[Fact, AutoInitShutdown]
+		public void EnsureSelectedItemVisible_SelectedItem ()
+		{
+			var source = new List<string> ();
+			for (int i = 0; i < 10; i++) {
+				source.Add ($"Item {i}");
+			}
+			var lv = new ListView (source) {
+				Width = 10,
+				Height = 5
+			};
+			Application.Top.Add (lv);
+			Application.Begin (Application.Top);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+Item 0
+Item 1
+Item 2
+Item 3
+Item 4", output);
+
+			lv.SelectedItem = 6;
+			Application.Refresh ();
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+Item 0
+Item 1
+Item 2
+Item 3
+Item 4", output);
+
+			lv.EnsureSelectedItemVisible ();
+			Application.Refresh ();
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+Item 2
+Item 3
+Item 4
+Item 5
+Item 6", output);
+		}
 	}
 	}
 }
 }

+ 1 - 1
UnitTests/PanelViewTests.cs → UnitTests/Views/PanelViewTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class PanelViewTests {
 	public class PanelViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 1 - 1
UnitTests/ProgressBarTests.cs → UnitTests/Views/ProgressBarTests.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ProgressBarTests {
 	public class ProgressBarTests {
 		[Fact]
 		[Fact]
 		[AutoInitShutdown]
 		[AutoInitShutdown]

+ 1 - 1
UnitTests/RadioGroupTests.cs → UnitTests/Views/RadioGroupTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class RadioGroupTests {
 	public class RadioGroupTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 22 - 31
UnitTests/ScrollBarViewTests.cs → UnitTests/Views/ScrollBarViewTests.cs

@@ -5,7 +5,7 @@ using System.Reflection;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ScrollBarViewTests {
 	public class ScrollBarViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -20,19 +20,11 @@ namespace Terminal.Gui.Views {
 		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
 		// 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.
 		// as a pair, and b) all unit test functions should be atomic.
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-		public class InitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
+		public class ScrollBarAutoInitShutdownAttribute : AutoInitShutdownAttribute {
 
 
 			public override void Before (MethodInfo methodUnderTest)
 			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;
+				base.Before (methodUnderTest);
 
 
 				ScrollBarViewTests._hostView = new HostView () {
 				ScrollBarViewTests._hostView = new HostView () {
 					Width = Dim.Fill (),
 					Width = Dim.Fill (),
@@ -43,14 +35,13 @@ namespace Terminal.Gui.Views {
 					Cols = 100
 					Cols = 100
 				};
 				};
 
 
-				top.Add (ScrollBarViewTests._hostView);
+				Application.Top.Add (ScrollBarViewTests._hostView);
 			}
 			}
 
 
 			public override void After (MethodInfo methodUnderTest)
 			public override void After (MethodInfo methodUnderTest)
 			{
 			{
-				Debug.WriteLine ($"After: {methodUnderTest.Name}");
 				ScrollBarViewTests._hostView = null;
 				ScrollBarViewTests._hostView = null;
-				Application.Shutdown ();
+				base.After (methodUnderTest);
 			}
 			}
 		}
 		}
 
 
@@ -113,7 +104,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Hosting_A_Null_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		public void Hosting_A_Null_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		{
 		{
 			Assert.Throws<ArgumentNullException> ("The host parameter can't be null.",
 			Assert.Throws<ArgumentNullException> ("The host parameter can't be null.",
@@ -123,7 +114,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Hosting_A_Null_SuperView_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		public void Hosting_A_Null_SuperView_View_To_A_ScrollBarView_Throws_ArgumentNullException ()
 		{
 		{
 			Assert.Throws<ArgumentNullException> ("The host SuperView parameter can't be null.",
 			Assert.Throws<ArgumentNullException> ("The host SuperView parameter can't be null.",
@@ -133,7 +124,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Hosting_Two_Vertical_ScrollBarView_Throws_ArgumentException ()
 		public void Hosting_Two_Vertical_ScrollBarView_Throws_ArgumentException ()
 		{
 		{
 			var top = new Toplevel ();
 			var top = new Toplevel ();
@@ -147,7 +138,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Hosting_Two_Horizontal_ScrollBarView_Throws_ArgumentException ()
 		public void Hosting_Two_Horizontal_ScrollBarView_Throws_ArgumentException ()
 		{
 		{
 			var top = new Toplevel ();
 			var top = new Toplevel ();
@@ -161,7 +152,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Scrolling_With_Default_Constructor_Do_Not_Scroll ()
 		public void Scrolling_With_Default_Constructor_Do_Not_Scroll ()
 		{
 		{
 			var sbv = new ScrollBarView {
 			var sbv = new ScrollBarView {
@@ -172,7 +163,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void Hosting_A_View_To_A_ScrollBarView ()
 		public void Hosting_A_View_To_A_ScrollBarView ()
 		{
 		{
 			RemoveHandlers ();
 			RemoveHandlers ();
@@ -198,7 +189,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void ChangedPosition_Update_The_Hosted_View ()
 		public void ChangedPosition_Update_The_Hosted_View ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -213,7 +204,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void ChangedPosition_Scrolling ()
 		public void ChangedPosition_Scrolling ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -240,7 +231,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void ChangedPosition_Negative_Value ()
 		public void ChangedPosition_Negative_Value ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -257,7 +248,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void DrawContent_Update_The_ScrollBarView_Position ()
 		public void DrawContent_Update_The_ScrollBarView_Position ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -274,7 +265,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void OtherScrollBarView_Not_Null ()
 		public void OtherScrollBarView_Not_Null ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -287,7 +278,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void ShowScrollIndicator_Check ()
 		public void ShowScrollIndicator_Check ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -299,7 +290,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void KeepContentAlwaysInViewport_True ()
 		public void KeepContentAlwaysInViewport_True ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -339,7 +330,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void KeepContentAlwaysInViewport_False ()
 		public void KeepContentAlwaysInViewport_False ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -361,7 +352,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[ScrollBarAutoInitShutdown]
 		public void AutoHideScrollBars_Check ()
 		public void AutoHideScrollBars_Check ()
 		{
 		{
 			Hosting_A_View_To_A_ScrollBarView ();
 			Hosting_A_View_To_A_ScrollBarView ();
@@ -457,7 +448,7 @@ namespace Terminal.Gui.Views {
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_True_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_True_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		{
 		{
 			var exception = Record.Exception (() => {
 			var exception = Record.Exception (() => {
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 
 				var top = Application.Top;
 				var top = Application.Top;
 
 
@@ -527,7 +518,7 @@ namespace Terminal.Gui.Views {
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_False_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_False_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		{
 		{
 			var exception = Record.Exception (() => {
 			var exception = Record.Exception (() => {
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 
 				var top = Application.Top;
 				var top = Application.Top;
 
 

+ 1 - 1
UnitTests/ScrollViewTests.cs → UnitTests/Views/ScrollViewTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class ScrollViewTests {
 	public class ScrollViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 

+ 2 - 2
UnitTests/StatusBarTests.cs → UnitTests/Views/StatusBarTests.cs

@@ -2,7 +2,7 @@
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class StatusBarTests {
 	public class StatusBarTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -36,7 +36,7 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (1, sb.Height);
 			Assert.Equal (1, sb.Height);
 
 
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 
 			sb = new StatusBar ();
 			sb = new StatusBar ();
 
 

+ 2 - 2
UnitTests/TabViewTests.cs → UnitTests/Views/TabViewTests.cs

@@ -8,7 +8,7 @@ using Xunit;
 using System.Globalization;
 using System.Globalization;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 
 
 	public class TabViewTests {
 	public class TabViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -763,7 +763,7 @@ namespace Terminal.Gui.Views {
 		private void InitFakeDriver ()
 		private void InitFakeDriver ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 		}
 		}
 	}
 	}

+ 118 - 1
UnitTests/TableViewTests.cs → UnitTests/Views/TableViewTests.cs

@@ -9,7 +9,7 @@ using System.Globalization;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using System.Reflection;
 using System.Reflection;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 
 
 	public class TableViewTests {
 	public class TableViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -646,6 +646,75 @@ namespace Terminal.Gui.Views {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
+		[Fact, AutoInitShutdown]
+		public void TestShiftClick_MultiSelect_TwoRowTable_FullRowSelect()
+		{
+			var tv = GetTwoRowSixColumnTable ();
+
+			tv.MultiSelect = true;
+			
+			// Clicking in bottom row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 3,
+				Flags = MouseFlags.Button1Clicked
+			});
+
+			// should select that row
+			Assert.Equal (1, tv.SelectedRow);
+
+			// shift clicking top row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 2,
+				Flags = MouseFlags.Button1Clicked | MouseFlags.ButtonShift
+			});
+
+			// should extend the selection
+			Assert.Equal (0, tv.SelectedRow);
+
+			var selected = tv.GetAllSelectedCells ().ToArray();
+
+			Assert.Contains (new Point(0,0), selected);
+			Assert.Contains (new Point (0, 1), selected);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void TestControlClick_MultiSelect_ThreeRowTable_FullRowSelect ()
+		{
+			var tv = GetTwoRowSixColumnTable ();
+			tv.Table.Rows.Add (1, 2, 3, 4, 5, 6);
+
+			tv.MultiSelect = true;
+
+			// Clicking in bottom row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 4,
+				Flags = MouseFlags.Button1Clicked
+			});
+
+			// should select that row
+			Assert.Equal (2, tv.SelectedRow);
+
+			// shift clicking top row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 2,
+				Flags = MouseFlags.Button1Clicked | MouseFlags.ButtonCtrl
+			});
+
+			// should extend the selection
+			// to include bottom and top row but not middle
+			Assert.Equal (0, tv.SelectedRow);
+
+			var selected = tv.GetAllSelectedCells ().ToArray ();
+
+			Assert.Contains (new Point (0, 0), selected);
+			Assert.DoesNotContain (new Point (0, 1), selected);
+			Assert.Contains (new Point (0, 2), selected);
+		}
+
 		[Theory]
 		[Theory]
 		[InlineData (false)]
 		[InlineData (false)]
 		[InlineData (true)]
 		[InlineData (true)]
@@ -1312,6 +1381,54 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (1, tableView.SelectedColumn);
 			Assert.Equal (1, tableView.SelectedColumn);
 		}
 		}
 
 
+
+		[InlineData(true)]
+		[InlineData (false)]
+		[Theory, AutoInitShutdown]
+		public void TestMoveStartEnd_WithFullRowSelect(bool withFullRowSelect)
+		{
+			var tableView = GetTwoRowSixColumnTable ();
+			tableView.FullRowSelect = withFullRowSelect;
+
+			tableView.SelectedRow = 1;
+			tableView.SelectedColumn = 1;
+
+			tableView.ProcessKey (new KeyEvent 
+			{
+				Key = Key.Home  | Key.CtrlMask
+			});
+
+			if(withFullRowSelect)
+			{
+				// Should not be any horizontal movement when
+				// using navigate to Start/End and FullRowSelect
+				Assert.Equal (1, tableView.SelectedColumn);
+				Assert.Equal (0, tableView.SelectedRow);
+			}
+			else
+			{
+				Assert.Equal (0, tableView.SelectedColumn);
+				Assert.Equal (0, tableView.SelectedRow);
+			}
+
+			tableView.ProcessKey (new KeyEvent 
+			{
+				Key = Key.End  | Key.CtrlMask
+			});
+
+			if(withFullRowSelect)
+			{
+				Assert.Equal (1, tableView.SelectedColumn);
+				Assert.Equal (1, tableView.SelectedRow);
+			}
+			else
+			{
+				Assert.Equal (5, tableView.SelectedColumn);
+				Assert.Equal (1, tableView.SelectedRow);
+			}
+
+		}
+
 		[InlineData (true)]
 		[InlineData (true)]
 		[InlineData (false)]
 		[InlineData (false)]
 		[Theory, AutoInitShutdown]
 		[Theory, AutoInitShutdown]

+ 157 - 130
UnitTests/TextFieldTests.cs → UnitTests/Views/TextFieldTests.cs

@@ -2,7 +2,7 @@
 using System.Reflection;
 using System.Reflection;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class TextFieldTests {
 	public class TextFieldTests {
 
 
 		// This class enables test functions annotated with the [InitShutdown] attribute
 		// This class enables test functions annotated with the [InitShutdown] attribute
@@ -11,11 +11,11 @@ namespace Terminal.Gui.Views {
 		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
 		// 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.
 		// as a pair, and b) all unit test functions should be atomic.
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-		public class InitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+		public class TextFieldTestsAutoInitShutdown : AutoInitShutdownAttribute {
 
 
 			public override void Before (MethodInfo methodUnderTest)
 			public override void Before (MethodInfo methodUnderTest)
 			{
 			{
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				base.Before (methodUnderTest);
 
 
 				//                                                    1         2         3 
 				//                                                    1         2         3 
 				//                                          01234567890123456789012345678901=32 (Length)
 				//                                          01234567890123456789012345678901=32 (Length)
@@ -25,14 +25,14 @@ namespace Terminal.Gui.Views {
 			public override void After (MethodInfo methodUnderTest)
 			public override void After (MethodInfo methodUnderTest)
 			{
 			{
 				TextFieldTests._textField = null;
 				TextFieldTests._textField = null;
-				Application.Shutdown ();
+				base.After (methodUnderTest);
 			}
 			}
 		}
 		}
 
 
 		private static TextField _textField;
 		private static TextField _textField;
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Changing_SelectedStart_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		public void Changing_SelectedStart_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		{
 		{
 			_textField.SelectedStart = 2;
 			_textField.SelectedStart = 2;
@@ -46,7 +46,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void SelectedStart_With_Value_Less_Than_Minus_One_Changes_To_Minus_One ()
 		public void SelectedStart_With_Value_Less_Than_Minus_One_Changes_To_Minus_One ()
 		{
 		{
 			_textField.SelectedStart = -2;
 			_textField.SelectedStart = -2;
@@ -56,7 +56,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void SelectedStart_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		public void SelectedStart_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 		{
 			_textField.CursorPosition = 2;
 			_textField.CursorPosition = 2;
@@ -67,7 +67,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void SelectedStart_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		public void SelectedStart_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		{
 		{
 			_textField.CursorPosition = 33;
 			_textField.CursorPosition = 33;
@@ -79,18 +79,18 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void SelectedStart_Greater_Than_CursorPosition_All_Selection_Is_Overwritten_On_Typing ()
 		public void SelectedStart_Greater_Than_CursorPosition_All_Selection_Is_Overwritten_On_Typing ()
 		{
 		{
 			_textField.SelectedStart = 19;
 			_textField.SelectedStart = 19;
 			_textField.CursorPosition = 12;
 			_textField.CursorPosition = 12;
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
-			Assert.Equal ("TAB to jump u text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump u text fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 		{
 			_textField.CursorPosition = -1;
 			_textField.CursorPosition = -1;
@@ -100,7 +100,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 		{
 			_textField.CursorPosition = 33;
 			_textField.CursorPosition = 33;
@@ -110,7 +110,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordForward_With_No_Selection ()
 		public void WordForward_With_No_Selection ()
 		{
 		{
 			_textField.CursorPosition = 0;
 			_textField.CursorPosition = 0;
@@ -161,7 +161,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordBackward_With_No_Selection ()
 		public void WordBackward_With_No_Selection ()
 		{
 		{
 			_textField.CursorPosition = _textField.Text.Length;
 			_textField.CursorPosition = _textField.Text.Length;
@@ -212,7 +212,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordForward_With_Selection ()
 		public void WordForward_With_Selection ()
 		{
 		{
 			_textField.CursorPosition = 0;
 			_textField.CursorPosition = 0;
@@ -264,7 +264,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordBackward_With_Selection ()
 		public void WordBackward_With_Selection ()
 		{
 		{
 			_textField.CursorPosition = _textField.Text.Length;
 			_textField.CursorPosition = _textField.Text.Length;
@@ -316,7 +316,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 		{
 			_textField.CursorPosition = 10;
 			_textField.CursorPosition = 10;
@@ -356,7 +356,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		{
 		{
 			_textField.CursorPosition = 10;
 			_textField.CursorPosition = 10;
@@ -390,7 +390,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 		{
 			//                           1         2         3         4         5    
 			//                           1         2         3         4         5    
@@ -474,7 +474,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 		{
 			//                           1         2         3         4         5    
 			//                           1         2         3         4         5    
@@ -558,7 +558,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		{
 		{
 			_textField.SelectedStart = -1;
 			_textField.SelectedStart = -1;
@@ -569,7 +569,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		{
 		{
 			_textField.SelectedStart = 20;
 			_textField.SelectedStart = 20;
@@ -581,45 +581,45 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		{
 		{
 			_textField.SelectedStart = 20;
 			_textField.SelectedStart = 20;
 			_textField.CursorPosition = 24;
 			_textField.CursorPosition = 24;
 			_textField.Copy ();
 			_textField.Copy ();
 			Assert.Equal ("text", _textField.SelectedText);
 			Assert.Equal ("text", _textField.SelectedText);
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.Paste ();
 			_textField.Paste ();
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.SelectedStart = 20;
 			_textField.SelectedStart = 20;
 			_textField.Cut ();
 			_textField.Cut ();
 			_textField.Paste ();
 			_textField.Paste ();
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		{
 		{
 			_textField.SelectedStart = 20;
 			_textField.SelectedStart = 20;
 			_textField.CursorPosition = 24;
 			_textField.CursorPosition = 24;
 			_textField.Copy ();
 			_textField.Copy ();
 			Assert.Equal ("text", _textField.SelectedText);
 			Assert.Equal ("text", _textField.SelectedText);
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.SelectedStart = -1;
 			_textField.SelectedStart = -1;
 			_textField.Paste ();
 			_textField.Paste ();
-			Assert.Equal ("TAB to jump between texttext fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between texttext fields.", _textField.Text.ToString ());
 			_textField.SelectedStart = 24;
 			_textField.SelectedStart = 24;
 			_textField.Cut ();
 			_textField.Cut ();
 			Assert.Null (_textField.SelectedText);
 			Assert.Null (_textField.SelectedText);
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.SelectedStart = -1;
 			_textField.SelectedStart = -1;
 			_textField.Paste ();
 			_textField.Paste ();
-			Assert.Equal ("TAB to jump between texttext fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between texttext fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Copy_Or_Cut__Not_Allowed_If_Secret_Is_True ()
 		public void Copy_Or_Cut__Not_Allowed_If_Secret_Is_True ()
 		{
 		{
 			_textField.Secret = true;
 			_textField.Secret = true;
@@ -637,7 +637,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Paste_Always_Clear_The_SelectedText ()
 		public void Paste_Always_Clear_The_SelectedText ()
 		{
 		{
 			_textField.SelectedStart = 20;
 			_textField.SelectedStart = 20;
@@ -649,7 +649,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void TextChanging_Event ()
 		public void TextChanging_Event ()
 		{
 		{
 			bool cancel = true;
 			bool cancel = true;
@@ -662,14 +662,14 @@ namespace Terminal.Gui.Views {
 			};
 			};
 
 
 			_textField.Text = "changing";
 			_textField.Text = "changing";
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			cancel = false;
 			cancel = false;
 			_textField.Text = "changing";
 			_textField.Text = "changing";
-			Assert.Equal ("changing", _textField.Text);
+			Assert.Equal ("changing", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void TextChanged_Event ()
 		public void TextChanged_Event ()
 		{
 		{
 			_textField.TextChanged += (e) => {
 			_textField.TextChanged += (e) => {
@@ -677,40 +677,40 @@ namespace Terminal.Gui.Views {
 			};
 			};
 
 
 			_textField.Text = "changed";
 			_textField.Text = "changed";
-			Assert.Equal ("changed", _textField.Text);
+			Assert.Equal ("changed", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Used_Is_True_By_Default ()
 		public void Used_Is_True_By_Default ()
 		{
 		{
 			_textField.CursorPosition = 10;
 			_textField.CursorPosition = 10;
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
-			Assert.Equal ("TAB to jumup between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumup between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
 			_textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
-			Assert.Equal ("TAB to jumusp between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumusp between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
 			_textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
-			Assert.Equal ("TAB to jumusep between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumusep between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
 			_textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
-			Assert.Equal ("TAB to jumusedp between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumusedp between text fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Used_Is_False ()
 		public void Used_Is_False ()
 		{
 		{
 			_textField.Used = false;
 			_textField.Used = false;
 			_textField.CursorPosition = 10;
 			_textField.CursorPosition = 10;
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
 			_textField.ProcessKey (new KeyEvent ((Key)0x75, new KeyModifiers ())); // u
-			Assert.Equal ("TAB to jumu between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumu between text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
 			_textField.ProcessKey (new KeyEvent ((Key)0x73, new KeyModifiers ())); // s
-			Assert.Equal ("TAB to jumusbetween text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumusbetween text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
 			_textField.ProcessKey (new KeyEvent ((Key)0x65, new KeyModifiers ())); // e
-			Assert.Equal ("TAB to jumuseetween text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumuseetween text fields.", _textField.Text.ToString ());
 			_textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
 			_textField.ProcessKey (new KeyEvent ((Key)0x64, new KeyModifiers ())); // d
-			Assert.Equal ("TAB to jumusedtween text fields.", _textField.Text);
+			Assert.Equal ("TAB to jumusedtween text fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -718,22 +718,22 @@ namespace Terminal.Gui.Views {
 		{
 		{
 			var tf = new TextField ("ABC");
 			var tf = new TextField ("ABC");
 			tf.EnsureFocus ();
 			tf.EnsureFocus ();
-			Assert.Equal ("ABC", tf.Text);
+			Assert.Equal ("ABC", tf.Text.ToString ());
 			Assert.Equal (3, tf.CursorPosition);
 			Assert.Equal (3, tf.CursorPosition);
 
 
 			// now delete the C
 			// now delete the C
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("AB", tf.Text);
+			Assert.Equal ("AB", tf.Text.ToString ());
 			Assert.Equal (2, tf.CursorPosition);
 			Assert.Equal (2, tf.CursorPosition);
 
 
 			// then delete the B
 			// then delete the B
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("A", tf.Text);
+			Assert.Equal ("A", tf.Text.ToString ());
 			Assert.Equal (1, tf.CursorPosition);
 			Assert.Equal (1, tf.CursorPosition);
 
 
 			// then delete the A
 			// then delete the A
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("", tf.Text);
+			Assert.Equal ("", tf.Text.ToString ());
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.Equal (0, tf.CursorPosition);
 		}
 		}
 
 
@@ -743,24 +743,24 @@ namespace Terminal.Gui.Views {
 			var tf = new TextField ("ABC");
 			var tf = new TextField ("ABC");
 			tf.EnsureFocus ();
 			tf.EnsureFocus ();
 			tf.CursorPosition = 2;
 			tf.CursorPosition = 2;
-			Assert.Equal ("ABC", tf.Text);
+			Assert.Equal ("ABC", tf.Text.ToString ());
 
 
 			// now delete the B
 			// now delete the B
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("AC", tf.Text);
+			Assert.Equal ("AC", tf.Text.ToString ());
 
 
 			// then delete the A
 			// then delete the A
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("C", tf.Text);
+			Assert.Equal ("C", tf.Text.ToString ());
 
 
 			// then delete nothing
 			// then delete nothing
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("C", tf.Text);
+			Assert.Equal ("C", tf.Text.ToString ());
 
 
 			// now delete the C
 			// now delete the C
 			tf.CursorPosition = 1;
 			tf.CursorPosition = 1;
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
-			Assert.Equal ("", tf.Text);
+			Assert.Equal ("", tf.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -769,35 +769,35 @@ namespace Terminal.Gui.Views {
 			var tf = new TextField ();
 			var tf = new TextField ();
 			tf.EnsureFocus ();
 			tf.EnsureFocus ();
 			tf.ProcessKey (new KeyEvent (Key.A, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.A, new KeyModifiers ()));
-			Assert.Equal ("A", tf.Text);
+			Assert.Equal ("A", tf.Text.ToString ());
 
 
 			// cancel the next keystroke
 			// cancel the next keystroke
 			tf.TextChanging += (e) => e.Cancel = e.NewText == "AB";
 			tf.TextChanging += (e) => e.Cancel = e.NewText == "AB";
 			tf.ProcessKey (new KeyEvent (Key.B, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.B, new KeyModifiers ()));
 
 
 			// B was canceled so should just be A
 			// B was canceled so should just be A
-			Assert.Equal ("A", tf.Text);
+			Assert.Equal ("A", tf.Text.ToString ());
 
 
 			// now delete the A
 			// now delete the A
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 			tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ()));
 
 
-			Assert.Equal ("", tf.Text);
+			Assert.Equal ("", tf.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void Text_Replaces_Tabs_With_Empty_String ()
 		public void Text_Replaces_Tabs_With_Empty_String ()
 		{
 		{
 			_textField.Text = "\t\tTAB to jump between text fields.";
 			_textField.Text = "\t\tTAB to jump between text fields.";
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 			_textField.Text = "";
 			_textField.Text = "";
 			Clipboard.Contents = "\t\tTAB to jump between text fields.";
 			Clipboard.Contents = "\t\tTAB to jump between text fields.";
 			_textField.Paste ();
 			_textField.Paste ();
-			Assert.Equal ("TAB to jump between text fields.", _textField.Text);
+			Assert.Equal ("TAB to jump between text fields.", _textField.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void TextField_SpaceHandling ()
 		public void TextField_SpaceHandling ()
 		{
 		{
 			var tf = new TextField () {
 			var tf = new TextField () {
@@ -825,7 +825,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextFieldTestsAutoInitShutdown]
 		public void CanFocus_False_Wont_Focus_With_Mouse ()
 		public void CanFocus_False_Wont_Focus_With_Mouse ()
 		{
 		{
 			var top = Application.Top;
 			var top = Application.Top;
@@ -901,201 +901,201 @@ namespace Terminal.Gui.Views {
 			Assert.False (tf.ReadOnly);
 			Assert.False (tf.ReadOnly);
 
 
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
-			Assert.Equal ("This is a test.", tf.Text);
+			Assert.Equal ("This is a test.", tf.Text.ToString ());
 			tf.CursorPosition = 0;
 			tf.CursorPosition = 0;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
-			Assert.Equal ("his is a test.", tf.Text);
+			Assert.Equal ("his is a test.", tf.Text.ToString ());
 			tf.ReadOnly = true;
 			tf.ReadOnly = true;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("his is a test.", tf.Text);
+			Assert.Equal ("his is a test.", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Delete, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Delete, new KeyModifiers ())));
-			Assert.Equal ("his is a test.", tf.Text);
+			Assert.Equal ("his is a test.", tf.Text.ToString ());
 			tf.ReadOnly = false;
 			tf.ReadOnly = false;
 			tf.CursorPosition = 1;
 			tf.CursorPosition = 1;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is is", tf.SelectedText);
 			Assert.Equal ("is is", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is is", tf.SelectedText);
 			Assert.Equal ("is is", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is is", tf.SelectedText);
 			Assert.Equal ("is is", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (" a test.", tf.SelectedText);
 			Assert.Equal (" a test.", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (" a test.", tf.SelectedText);
 			Assert.Equal (" a test.", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (" a test.", tf.SelectedText);
 			Assert.Equal (" a test.", tf.SelectedText);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.Equal (0, tf.CursorPosition);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Home | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.Equal (0, tf.CursorPosition);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.A | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.Equal (0, tf.CursorPosition);
 			tf.CursorPosition = 5;
 			tf.CursorPosition = 5;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("s", tf.SelectedText);
 			Assert.Equal ("s", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is", tf.SelectedText);
 			Assert.Equal ("is", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("s", tf.SelectedText);
 			Assert.Equal ("s", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			tf.CursorPosition = 7;
 			tf.CursorPosition = 7;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("a", tf.SelectedText);
 			Assert.Equal ("a", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is a", tf.SelectedText);
 			Assert.Equal ("is a", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.ShiftMask | Key.AltMask), new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.ShiftMask | Key.AltMask), new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is is a", tf.SelectedText);
 			Assert.Equal ("is is a", tf.SelectedText);
 			tf.CursorPosition = 3;
 			tf.CursorPosition = 3;
 			tf.SelectedStart = -1;
 			tf.SelectedStart = -1;
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is ", tf.SelectedText);
 			Assert.Equal ("is ", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.ShiftMask | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is a ", tf.SelectedText);
 			Assert.Equal ("is a ", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.ShiftMask | Key.AltMask), new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.ShiftMask | Key.AltMask), new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal ("is a test.", tf.SelectedText);
 			Assert.Equal ("is a test.", tf.SelectedText);
 			Assert.Equal (13, tf.CursorPosition);
 			Assert.Equal (13, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Null (tf.SelectedText);
 			Assert.Null (tf.SelectedText);
 			Assert.Equal (12, tf.CursorPosition);
 			Assert.Equal (12, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (11, tf.CursorPosition);
 			Assert.Equal (11, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (13, tf.CursorPosition);
 			Assert.Equal (13, tf.CursorPosition);
 			tf.CursorPosition = 0;
 			tf.CursorPosition = 0;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.End | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (13, tf.CursorPosition);
 			Assert.Equal (13, tf.CursorPosition);
 			tf.CursorPosition = 0;
 			tf.CursorPosition = 0;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.E | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (13, tf.CursorPosition);
 			Assert.Equal (13, tf.CursorPosition);
 			tf.CursorPosition = 0;
 			tf.CursorPosition = 0;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (1, tf.CursorPosition);
 			Assert.Equal (1, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.F | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.F | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.Equal (2, tf.CursorPosition);
 			Assert.Equal (2, tf.CursorPosition);
 			tf.CursorPosition = 9;
 			tf.CursorPosition = 9;
 			tf.ReadOnly = true;
 			tf.ReadOnly = true;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			tf.ReadOnly = false;
 			tf.ReadOnly = false;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
-			Assert.Equal ("est.", Clipboard.Contents);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
+			Assert.Equal ("est.", Clipboard.Contents.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Z | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Z | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.AltMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.AltMask, new KeyModifiers ())));
-			Assert.Equal ("is is a test.", tf.Text);
+			Assert.Equal ("is is a test.", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (8, tf.CursorPosition);
 			Assert.Equal (8, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorUp | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (6, tf.CursorPosition);
 			Assert.Equal (6, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.AltMask), new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'B' + Key.AltMask), new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (3, tf.CursorPosition);
 			Assert.Equal (3, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorRight | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (6, tf.CursorPosition);
 			Assert.Equal (6, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.CursorDown | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (8, tf.CursorPosition);
 			Assert.Equal (8, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.AltMask), new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent ((Key)((int)'F' + Key.AltMask), new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (9, tf.CursorPosition);
 			Assert.Equal (9, tf.CursorPosition);
 			Assert.True (tf.Used);
 			Assert.True (tf.Used);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.InsertChar, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.InsertChar, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
 			Assert.Equal (9, tf.CursorPosition);
 			Assert.Equal (9, tf.CursorPosition);
 			Assert.False (tf.Used);
 			Assert.False (tf.Used);
 			tf.SelectedStart = 3;
 			tf.SelectedStart = 3;
 			tf.CursorPosition = 7;
 			tf.CursorPosition = 7;
 			Assert.Equal ("is a", tf.SelectedText);
 			Assert.Equal ("is a", tf.SelectedText);
-			Assert.Equal ("est.", Clipboard.Contents);
+			Assert.Equal ("est.", Clipboard.Contents.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
-			Assert.Equal ("is a", Clipboard.Contents);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
+			Assert.Equal ("is a", Clipboard.Contents.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is  t", tf.Text);
-			Assert.Equal ("is a", Clipboard.Contents);
+			Assert.Equal ("is  t", tf.Text.ToString ());
+			Assert.Equal ("is a", Clipboard.Contents.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.V | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.V | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("is is a t", tf.Text);
-			Assert.Equal ("is a", Clipboard.Contents);
+			Assert.Equal ("is is a t", tf.Text.ToString ());
+			Assert.Equal ("is a", Clipboard.Contents.ToString ());
 			Assert.Equal (7, tf.CursorPosition);
 			Assert.Equal (7, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ())));
-			Assert.Equal (" t", tf.Text);
-			Assert.Equal ("is is a", Clipboard.Contents);
+			Assert.Equal (" t", tf.Text.ToString ());
+			Assert.Equal ("is is a", Clipboard.Contents.ToString ());
 			tf.Text = "TAB to jump between text fields.";
 			tf.Text = "TAB to jump between text fields.";
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.Equal (0, tf.CursorPosition);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("to jump between text fields.", tf.Text);
+			Assert.Equal ("to jump between text fields.", tf.Text.ToString ());
 			tf.CursorPosition = tf.Text.Length;
 			tf.CursorPosition = tf.Text.Length;
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask, new KeyModifiers ())));
-			Assert.Equal ("to jump between text ", tf.Text);
+			Assert.Equal ("to jump between text ", tf.Text.ToString ());
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.T | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.T | Key.CtrlMask, new KeyModifiers ())));
 			Assert.Equal ("to jump between text ", tf.SelectedText);
 			Assert.Equal ("to jump between text ", tf.SelectedText);
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ())));
-			Assert.Equal ("", tf.Text);
+			Assert.Equal ("", tf.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -1134,7 +1134,7 @@ namespace Terminal.Gui.Views {
 			Application.Top.Add (tf);
 			Application.Top.Add (tf);
 			Application.Begin (Application.Top);
 			Application.Begin (Application.Top);
 
 
-			Assert.Equal ("-1", tf.Text);
+			Assert.Equal ("-1", tf.Text.ToString ());
 
 
 			// InsertText
 			// InsertText
 			tf.SelectedStart = 1;
 			tf.SelectedStart = 1;
@@ -1144,7 +1144,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D2, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.D2, new KeyModifiers ())));
 			Assert.Equal ("-2", newText);
 			Assert.Equal ("-2", newText);
 			Assert.Equal ("-1", oldText);
 			Assert.Equal ("-1", oldText);
-			Assert.Equal ("-2", tf.Text);
+			Assert.Equal ("-2", tf.Text.ToString ());
 
 
 			// DeleteCharLeft
 			// DeleteCharLeft
 			tf.SelectedStart = 1;
 			tf.SelectedStart = 1;
@@ -1154,7 +1154,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())));
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-2", oldText);
 			Assert.Equal ("-2", oldText);
-			Assert.Equal ("-", tf.Text);
+			Assert.Equal ("-", tf.Text.ToString ());
 
 
 			// DeleteCharRight
 			// DeleteCharRight
 			tf.Text = "-1";
 			tf.Text = "-1";
@@ -1165,7 +1165,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.DeleteChar, new KeyModifiers ())));
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-1", oldText);
 			Assert.Equal ("-1", oldText);
-			Assert.Equal ("-", tf.Text);
+			Assert.Equal ("-", tf.Text.ToString ());
 
 
 			// Cut
 			// Cut
 			tf.Text = "-1";
 			tf.Text = "-1";
@@ -1176,7 +1176,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ())));
 			Assert.True (tf.ProcessKey (new KeyEvent (Key.X | Key.CtrlMask, new KeyModifiers ())));
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-", newText);
 			Assert.Equal ("-1", oldText);
 			Assert.Equal ("-1", oldText);
-			Assert.Equal ("-", tf.Text);
+			Assert.Equal ("-", tf.Text.ToString ());
 		}
 		}
 
 
 		[Fact]
 		[Fact]
@@ -1296,5 +1296,32 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ($"{text}A", tf.Text);
 			Assert.Equal ($"{text}A", tf.Text);
 			Assert.True (tf.IsDirty);
 			Assert.True (tf.IsDirty);
 		}
 		}
+
+		[InlineData ("a")] // Lower than selection
+		[InlineData ("aaaaaaaaaaa")] // Greater than selection
+		[InlineData ("aaaa")] // Equal than selection
+		[Theory]
+		public void TestSetTextAndMoveCursorToEnd_WhenExistingSelection (string newText)
+		{
+			var tf = new TextField ();
+			tf.Text = "fish";
+			tf.CursorPosition = tf.Text.Length;
+
+			tf.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ()));
+
+			tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask, new KeyModifiers { Shift = true }));
+			tf.ProcessKey (new KeyEvent (Key.CursorLeft | Key.ShiftMask, new KeyModifiers { Shift = true }));
+
+			Assert.Equal (1, tf.CursorPosition);
+			Assert.Equal (2, tf.SelectedLength);
+			Assert.Equal ("is", tf.SelectedText);
+
+			tf.Text = newText;
+			tf.CursorPosition = tf.Text.Length;
+
+			Assert.Equal (newText.Length, tf.CursorPosition);
+			Assert.Equal (0, tf.SelectedLength);
+			Assert.Null (tf.SelectedText);
+		}
 	}
 	}
 }
 }

+ 1 - 1
UnitTests/TextValidateFieldTests.cs → UnitTests/Views/TextValidateFieldTests.cs

@@ -5,7 +5,7 @@ using Terminal.Gui.TextValidateProviders;
 
 
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 
 
 	public class TextValidateField_NET_Provider_Tests {
 	public class TextValidateField_NET_Provider_Tests {
 
 

+ 83 - 86
UnitTests/TextViewTests.cs → UnitTests/Views/TextViewTests.cs

@@ -6,7 +6,7 @@ using System.Text.RegularExpressions;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class TextViewTests {
 	public class TextViewTests {
 		private static TextView _textView;
 		private static TextView _textView;
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
@@ -22,16 +22,12 @@ namespace Terminal.Gui.Views {
 		// This is necessary because a) Application is a singleton and Init/Shutdown must be called
 		// 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.
 		// as a pair, and b) all unit test functions should be atomic.
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 		[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-		public class InitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+		public class TextViewTestsAutoInitShutdown : AutoInitShutdownAttribute {
 
 
 			public static string txt = "TAB to jump between text fields.";
 			public static string txt = "TAB to jump between text fields.";
 			public override void Before (MethodInfo methodUnderTest)
 			public override void Before (MethodInfo methodUnderTest)
 			{
 			{
-				if (_textView != null) {
-					throw new InvalidOperationException ("After did not run.");
-				}
-
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				base.Before (methodUnderTest);
 
 
 				//                   1         2         3 
 				//                   1         2         3 
 				//         01234567890123456789012345678901=32 (Length)
 				//         01234567890123456789012345678901=32 (Length)
@@ -47,12 +43,12 @@ namespace Terminal.Gui.Views {
 			public override void After (MethodInfo methodUnderTest)
 			public override void After (MethodInfo methodUnderTest)
 			{
 			{
 				_textView = null;
 				_textView = null;
-				Application.Shutdown ();
+				base.After (methodUnderTest);
 			}
 			}
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Changing_Selection_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		public void Changing_Selection_Or_CursorPosition_Update_SelectedLength_And_SelectedText ()
 		{
 		{
 			_textView.SelectionStartColumn = 2;
 			_textView.SelectionStartColumn = 2;
@@ -69,7 +65,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Selection_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		public void Selection_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 		{
 			_textView.SelectionStartColumn = -2;
 			_textView.SelectionStartColumn = -2;
@@ -81,7 +77,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Selection_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		public void Selection_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 		{
 			_textView.CursorPosition = new Point (2, 0);
 			_textView.CursorPosition = new Point (2, 0);
@@ -94,7 +90,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Selection_With_Empty_Text ()
 		public void Selection_With_Empty_Text ()
 		{
 		{
 			_textView = new TextView ();
 			_textView = new TextView ();
@@ -108,7 +104,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Selection_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		public void Selection_And_CursorPosition_With_Value_Greater_Than_Text_Length_Changes_Both_To_Text_Length ()
 		{
 		{
 			_textView.CursorPosition = new Point (33, 2);
 			_textView.CursorPosition = new Point (33, 2);
@@ -123,7 +119,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		public void CursorPosition_With_Value_Less_Than_Zero_Changes_To_Zero ()
 		{
 		{
 			_textView.CursorPosition = new Point (-1, -1);
 			_textView.CursorPosition = new Point (-1, -1);
@@ -134,7 +130,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		public void CursorPosition_With_Value_Greater_Than_Text_Length_Changes_To_Text_Length ()
 		{
 		{
 			_textView.CursorPosition = new Point (33, 1);
 			_textView.CursorPosition = new Point (33, 1);
@@ -145,7 +141,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordForward_With_No_Selection ()
 		public void WordForward_With_No_Selection ()
 		{
 		{
 			_textView.CursorPosition = new Point (0, 0);
 			_textView.CursorPosition = new Point (0, 0);
@@ -208,7 +204,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordBackward_With_No_Selection ()
 		public void WordBackward_With_No_Selection ()
 		{
 		{
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
@@ -271,7 +267,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordForward_With_Selection ()
 		public void WordForward_With_Selection ()
 		{
 		{
 			_textView.CursorPosition = new Point (0, 0);
 			_textView.CursorPosition = new Point (0, 0);
@@ -336,7 +332,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordBackward_With_Selection ()
 		public void WordBackward_With_Selection ()
 		{
 		{
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
 			_textView.CursorPosition = new Point (_textView.Text.Length, 0);
@@ -401,7 +397,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordForward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		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);
 			_textView.CursorPosition = new Point (10, 0);
@@ -450,7 +446,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordBackward_With_The_Same_Values_For_SelectedStart_And_CursorPosition_And_Not_Starting_At_Beginning_Of_The_Text ()
 		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);
 			_textView.CursorPosition = new Point (10, 0);
@@ -491,7 +487,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		public void WordForward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 		{
 			//                          1         2         3         4         5    
 			//                          1         2         3         4         5    
@@ -597,7 +593,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		public void WordBackward_With_No_Selection_And_With_More_Than_Only_One_Whitespace_And_With_Only_One_Letter ()
 		{
 		{
 			//                          1         2         3         4         5    
 			//                          1         2         3         4         5    
@@ -703,7 +699,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordBackward_Multiline_With_Selection ()
 		public void WordBackward_Multiline_With_Selection ()
 		{
 		{
 			//		          4         3          2         1
 			//		          4         3          2         1
@@ -818,7 +814,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordForward_Multiline_With_Selection ()
 		public void WordForward_Multiline_With_Selection ()
 		{
 		{
 			//			    1         2          3         4
 			//			    1         2          3         4
@@ -932,7 +928,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ()
 		public void Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ()
 		{
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -945,26 +941,26 @@ namespace Terminal.Gui.Views {
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()));
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.Y);
 					Assert.Equal (0, _textView.CursorPosition.Y);
-					Assert.Equal ($"{Environment.NewLine}This is the second line.", _textView.Text);
-					Assert.Equal ("This is the first line.", Clipboard.Contents);
+					Assert.Equal ($"{Environment.NewLine}This is the second line.", _textView.Text.ToString ());
+					Assert.Equal ("This is the first line.", Clipboard.Contents.ToString ());
 					break;
 					break;
 				case 1:
 				case 1:
 					_textView.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.DeleteChar | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.Y);
 					Assert.Equal (0, _textView.CursorPosition.Y);
-					Assert.Equal ("This is the second line.", _textView.Text);
-					Assert.Equal ($"This is the first line.{Environment.NewLine}", Clipboard.Contents);
+					Assert.Equal ("This is the second line.", _textView.Text.ToString ());
+					Assert.Equal ($"This is the first line.{Environment.NewLine}", Clipboard.Contents.ToString());
 					break;
 					break;
 				case 2:
 				case 2:
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.CtrlMask, new KeyModifiers ()));
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.Y);
 					Assert.Equal (0, _textView.CursorPosition.Y);
-					Assert.Equal ("", _textView.Text);
-					Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.", Clipboard.Contents);
+					Assert.Equal ("", _textView.Text.ToString ());
+					Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.", Clipboard.Contents.ToString ());
 
 
 					// Paste
 					// Paste
 					_textView.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()));
-					Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.", _textView.Text);
+					Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.", _textView.Text.ToString ());
 					break;
 					break;
 				default:
 				default:
 					iterationsFinished = true;
 					iterationsFinished = true;
@@ -975,7 +971,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ()
 		public void Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ()
 		{
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -989,26 +985,26 @@ namespace Terminal.Gui.Views {
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ()));
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (1, _textView.CursorPosition.Y);
 					Assert.Equal (1, _textView.CursorPosition.Y);
-					Assert.Equal ($"This is the first line.{Environment.NewLine}", _textView.Text);
-					Assert.Equal ($"This is the second line.", Clipboard.Contents);
+					Assert.Equal ($"This is the first line.{Environment.NewLine}", _textView.Text.ToString());
+					Assert.Equal ($"This is the second line.", Clipboard.Contents.ToString ());
 					break;
 					break;
 				case 1:
 				case 1:
 					_textView.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.Backspace | Key.CtrlMask | Key.ShiftMask, new KeyModifiers ()));
 					Assert.Equal (23, _textView.CursorPosition.X);
 					Assert.Equal (23, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.Y);
 					Assert.Equal (0, _textView.CursorPosition.Y);
-					Assert.Equal ("This is the first line.", _textView.Text);
-					Assert.Equal ($"This is the second line.{Environment.NewLine}", Clipboard.Contents);
+					Assert.Equal ("This is the first line.", _textView.Text.ToString ());
+					Assert.Equal ($"This is the second line.{Environment.NewLine}", Clipboard.Contents.ToString ());
 					break;
 					break;
 				case 2:
 				case 2:
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.K | Key.AltMask, new KeyModifiers ()));
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.X);
 					Assert.Equal (0, _textView.CursorPosition.Y);
 					Assert.Equal (0, _textView.CursorPosition.Y);
-					Assert.Equal ("", _textView.Text);
-					Assert.Equal ($"This is the second line.{Environment.NewLine}This is the first line.", Clipboard.Contents);
+					Assert.Equal ("", _textView.Text.ToString ());
+					Assert.Equal ($"This is the second line.{Environment.NewLine}This is the first line.", Clipboard.Contents.ToString ());
 
 
 					// Paste inverted
 					// Paste inverted
 					_textView.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()));
 					_textView.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()));
-					Assert.Equal ($"This is the second line.{Environment.NewLine}This is the first line.", _textView.Text);
+					Assert.Equal ($"This is the second line.{Environment.NewLine}This is the first line.", _textView.Text.ToString ());
 					break;
 					break;
 				default:
 				default:
 					iterationsFinished = true;
 					iterationsFinished = true;
@@ -1019,7 +1015,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_Delete_WordForward ()
 		public void Kill_Delete_WordForward ()
 		{
 		{
 			_textView.Text = "This is the first line.";
 			_textView.Text = "This is the first line.";
@@ -1063,7 +1059,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_Delete_WordBackward ()
 		public void Kill_Delete_WordBackward ()
 		{
 		{
 			_textView.Text = "This is the first line.";
 			_textView.Text = "This is the first line.";
@@ -1108,7 +1104,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_Delete_WordForward_Multiline ()
 		public void Kill_Delete_WordForward_Multiline ()
 		{
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -1188,7 +1184,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Kill_Delete_WordBackward_Multiline ()
 		public void Kill_Delete_WordBackward_Multiline ()
 		{
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.";
 			_textView.Text = "This is the first line.\nThis is the second line.";
@@ -1268,7 +1264,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		public void Copy_Or_Cut_Null_If_No_Selection ()
 		{
 		{
 			_textView.SelectionStartColumn = 0;
 			_textView.SelectionStartColumn = 0;
@@ -1280,7 +1276,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		public void Copy_Or_Cut_Not_Null_If_Has_Selection ()
 		{
 		{
 			_textView.SelectionStartColumn = 20;
 			_textView.SelectionStartColumn = 20;
@@ -1293,7 +1289,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		public void Copy_Or_Cut_And_Paste_With_Selection ()
 		{
 		{
 			_textView.SelectionStartColumn = 20;
 			_textView.SelectionStartColumn = 20;
@@ -1312,7 +1308,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		public void Copy_Or_Cut_And_Paste_With_No_Selection ()
 		{
 		{
 			_textView.SelectionStartColumn = 20;
 			_textView.SelectionStartColumn = 20;
@@ -1347,7 +1343,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Cut_Not_Allowed_If_ReadOnly_Is_True ()
 		public void Cut_Not_Allowed_If_ReadOnly_Is_True ()
 		{
 		{
 			_textView.ReadOnly = true;
 			_textView.ReadOnly = true;
@@ -1368,7 +1364,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Paste_Always_Clear_The_SelectedText ()
 		public void Paste_Always_Clear_The_SelectedText ()
 		{
 		{
 			_textView.SelectionStartColumn = 20;
 			_textView.SelectionStartColumn = 20;
@@ -1381,7 +1377,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TextChanged_Event ()
 		public void TextChanged_Event ()
 		{
 		{
 			_textView.TextChanged += () => {
 			_textView.TextChanged += () => {
@@ -1396,7 +1392,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TextChanged_Event_NoFires_OnTyping ()
 		public void TextChanged_Event_NoFires_OnTyping ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
@@ -1412,7 +1408,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Used_Is_True_By_Default ()
 		public void Used_Is_True_By_Default ()
 		{
 		{
 			_textView.CursorPosition = new Point (10, 0);
 			_textView.CursorPosition = new Point (10, 0);
@@ -1428,7 +1424,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Used_Is_False ()
 		public void Used_Is_False ()
 		{
 		{
 			_textView.Used = false;
 			_textView.Used = false;
@@ -1445,7 +1441,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Copy_Without_Selection ()
 		public void Copy_Without_Selection ()
 		{
 		{
 			_textView.Text = "This is the first line.\nThis is the second line.\n";
 			_textView.Text = "This is the first line.\nThis is the second line.\n";
@@ -1464,7 +1460,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TabWidth_Setting_To_Zero_Keeps_AllowsTab ()
 		public void TabWidth_Setting_To_Zero_Keeps_AllowsTab ()
 		{
 		{
 			Assert.Equal (4, _textView.TabWidth);
 			Assert.Equal (4, _textView.TabWidth);
@@ -1483,7 +1479,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void AllowsTab_Setting_To_True_Changes_TabWidth_To_Default_If_It_Is_Zero ()
 		public void AllowsTab_Setting_To_True_Changes_TabWidth_To_Default_If_It_Is_Zero ()
 		{
 		{
 			_textView.TabWidth = 0;
 			_textView.TabWidth = 0;
@@ -1499,7 +1495,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void AllowsReturn_Setting_To_True_Changes_Multiline_To_True_If_It_Is_False ()
 		public void AllowsReturn_Setting_To_True_Changes_Multiline_To_True_If_It_Is_False ()
 		{
 		{
 			Assert.True (_textView.AllowsReturn);
 			Assert.True (_textView.AllowsReturn);
@@ -1521,7 +1517,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Multiline_Setting_Changes_AllowsReturn_AllowsTab_Height_WordWrap ()
 		public void Multiline_Setting_Changes_AllowsReturn_AllowsTab_Height_WordWrap ()
 		{
 		{
 			Assert.True (_textView.Multiline);
 			Assert.True (_textView.Multiline);
@@ -1556,7 +1552,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Tab_Test_Follow_By_BackTab ()
 		public void Tab_Test_Follow_By_BackTab ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -1592,7 +1588,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void BackTab_Test_Follow_By_Tab ()
 		public void BackTab_Test_Follow_By_Tab ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -1635,7 +1631,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight ()
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -1678,7 +1674,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Tab_Test_Follow_By_BackTab_With_Text ()
 		public void Tab_Test_Follow_By_BackTab_With_Text ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -1714,7 +1710,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Tab_Test_Follow_By_Home_And_Then_Follow_By_End_And_Then_Follow_By_BackTab_With_Text ()
 		public void Tab_Test_Follow_By_Home_And_Then_Follow_By_End_And_Then_Follow_By_BackTab_With_Text ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -1772,7 +1768,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight_With_Text ()
 		public void Tab_Test_Follow_By_CursorLeft_And_Then_Follow_By_CursorRight_With_Text ()
 		{
 		{
 			Application.Top.Add (_textView);
 			Application.Top.Add (_textView);
@@ -2020,7 +2016,7 @@ namespace Terminal.Gui.Views {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordWrap_WrapModel_Output ()
 		public void WordWrap_WrapModel_Output ()
 		{
 		{
 			//          0123456789
 			//          0123456789
@@ -2103,7 +2099,7 @@ a
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void WordWrap_ReadOnly_CursorPosition_SelectedText_Copy ()
 		public void WordWrap_ReadOnly_CursorPosition_SelectedText_Copy ()
 		{
 		{
 			//          0123456789
 			//          0123456789
@@ -2228,7 +2224,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void BottomOffset_Sets_To_Zero_Adjust_TopRow ()
 		public void BottomOffset_Sets_To_Zero_Adjust_TopRow ()
 		{
 		{
 			string text = "";
 			string text = "";
@@ -2258,7 +2254,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void RightOffset_Sets_To_Zero_Adjust_leftColumn ()
 		public void RightOffset_Sets_To_Zero_Adjust_leftColumn ()
 		{
 		{
 			string text = "";
 			string text = "";
@@ -2288,7 +2284,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TextView_SpaceHandling ()
 		public void TextView_SpaceHandling ()
 		{
 		{
 			var tv = new TextView () {
 			var tv = new TextView () {
@@ -2316,7 +2312,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void CanFocus_False_Wont_Focus_With_Mouse ()
 		public void CanFocus_False_Wont_Focus_With_Mouse ()
 		{
 		{
 			var top = Application.Top;
 			var top = Application.Top;
@@ -2383,7 +2379,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void DesiredCursorVisibility_Vertical_Navigation ()
 		public void DesiredCursorVisibility_Vertical_Navigation ()
 		{
 		{
 			string text = "";
 			string text = "";
@@ -2422,7 +2418,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void DesiredCursorVisibility_Horizontal_Navigation ()
 		public void DesiredCursorVisibility_Horizontal_Navigation ()
 		{
 		{
 			string text = "";
 			string text = "";
@@ -5942,7 +5938,7 @@ line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void Mouse_Button_Shift_Preserves_Selection ()
 		public void Mouse_Button_Shift_Preserves_Selection ()
 		{
 		{
 			Assert.Equal ("TAB to jump between text fields.", _textView.Text);
 			Assert.Equal ("TAB to jump between text fields.", _textView.Text);
@@ -6333,7 +6329,7 @@ This is the second line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TextView_InsertText_Newline_LF ()
 		public void TextView_InsertText_Newline_LF ()
 		{
 		{
 			var tv = new TextView {
 			var tv = new TextView {
@@ -6402,7 +6398,7 @@ This is the second line.
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		[InitShutdown]
+		[TextViewTestsAutoInitShutdown]
 		public void TextView_InsertText_Newline_CRLF ()
 		public void TextView_InsertText_Newline_CRLF ()
 		{
 		{
 			var tv = new TextView {
 			var tv = new TextView {
@@ -6621,7 +6617,7 @@ This is the second line.
 			Assert.Equal ("Yay", tv.Text.ToString ());
 			Assert.Equal ("Yay", tv.Text.ToString ());
 		}
 		}
 
 
-		[Fact, InitShutdown]
+		[Fact, TextViewTestsAutoInitShutdown]
 		public void ContentsChanged_Event_Fires_Using_Kill_Delete_Tests ()
 		public void ContentsChanged_Event_Fires_Using_Kill_Delete_Tests ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
@@ -6647,7 +6643,8 @@ This is the second line.
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 		}
 		}
 
 
-		[Fact, InitShutdown]
+
+		[Fact, TextViewTestsAutoInitShutdown]
 		public void ContentsChanged_Event_Fires_Using_Copy_Or_Cut_Tests ()
 		public void ContentsChanged_Event_Fires_Using_Copy_Or_Cut_Tests ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
@@ -6659,7 +6656,7 @@ This is the second line.
 			var expectedEventCount = 1;
 			var expectedEventCount = 1;
 
 
 			// reset
 			// reset
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 3;
 			expectedEventCount += 3;
@@ -6668,7 +6665,7 @@ This is the second line.
 
 
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 3;
 			expectedEventCount += 3;
@@ -6677,7 +6674,7 @@ This is the second line.
 
 
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 1;
 			expectedEventCount += 1;
@@ -6686,7 +6683,7 @@ This is the second line.
 
 
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 1;
 			expectedEventCount += 1;
@@ -6695,7 +6692,7 @@ This is the second line.
 
 
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 4;
 			expectedEventCount += 4;
@@ -6704,7 +6701,7 @@ This is the second line.
 
 
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
-			_textView.Text = InitShutdown.txt;
+			_textView.Text = TextViewTestsAutoInitShutdown.txt;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
 			expectedEventCount += 4;
 			expectedEventCount += 4;
@@ -6712,7 +6709,7 @@ This is the second line.
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 		}
 		}
 
 
-		[Fact, InitShutdown]
+		[Fact, TextViewTestsAutoInitShutdown]
 		public void ContentsChanged_Event_Fires_On_Undo_Redo ()
 		public void ContentsChanged_Event_Fires_On_Undo_Redo ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;

+ 1 - 1
UnitTests/TimeFieldTests.cs → UnitTests/Views/TimeFieldTests.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 	public class TimeFieldTests {
 	public class TimeFieldTests {
 		[Fact]
 		[Fact]
 		public void Constructors_Defaults ()
 		public void Constructors_Defaults ()

+ 2 - 2
UnitTests/TreeViewTests.cs → UnitTests/Views/TreeViewTests.cs

@@ -8,7 +8,7 @@ using Terminal.Gui.Trees;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 
 
-namespace Terminal.Gui.Views {
+namespace Terminal.Gui.ViewTests {
 
 
 	public class TreeViewTests {
 	public class TreeViewTests {
 
 
@@ -953,7 +953,7 @@ namespace Terminal.Gui.Views {
 		private void InitFakeDriver ()
 		private void InitFakeDriver ()
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			driver.Init (() => { });
 		}
 		}
 	}
 	}

+ 71 - 12
UnitTests/ViewTests.cs → UnitTests/Views/ViewTests.cs

@@ -1,12 +1,12 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
-using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
+//using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.Core {
+namespace Terminal.Gui.ViewTests {
 	public class ViewTests {
 	public class ViewTests {
 		readonly ITestOutputHelper output;
 		readonly ITestOutputHelper output;
 
 
@@ -574,7 +574,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Initialized_Event_Comparing_With_Added_Event ()
 		public void Initialized_Event_Comparing_With_Added_Event ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = new Toplevel () { Id = "0", };
 			var t = new Toplevel () { Id = "0", };
 
 
@@ -673,7 +673,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Initialized_Event_Will_Be_Invoked_When_Added_Dynamically ()
 		public void Initialized_Event_Will_Be_Invoked_When_Added_Dynamically ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = new Toplevel () { Id = "0", };
 			var t = new Toplevel () { Id = "0", };
 
 
@@ -782,7 +782,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void CanFocus_Faced_With_Container_Before_Run ()
 		public void CanFocus_Faced_With_Container_Before_Run ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -819,7 +819,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void CanFocus_Faced_With_Container_After_Run ()
 		public void CanFocus_Faced_With_Container_After_Run ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -862,7 +862,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too ()
 		public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -897,7 +897,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True ()
 		public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 
 
@@ -941,7 +941,7 @@ namespace Terminal.Gui.Core {
 		{
 		{
 			// Non-regression test for #882 (NullReferenceException during keyboard navigation when Focused is null)
 			// Non-regression test for #882 (NullReferenceException during keyboard navigation when Focused is null)
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			Application.Top.Ready += () => {
 			Application.Top.Ready += () => {
 				Assert.Null (Application.Top.Focused);
 				Assert.Null (Application.Top.Focused);
@@ -959,7 +959,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void Multi_Thread_Toplevels ()
 		public void Multi_Thread_Toplevels ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			var t = Application.Top;
 			var t = Application.Top;
 			var w = new Window ();
 			var w = new Window ();
@@ -1148,7 +1148,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		[Fact]
 		public void KeyPress_Handled_To_True_Prevents_Changes ()
 		public void KeyPress_Handled_To_True_Prevents_Changes ()
 		{
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 
 			Console.MockKeyPresses.Push (new ConsoleKeyInfo ('N', ConsoleKey.N, false, false, false));
 			Console.MockKeyPresses.Push (new ConsoleKeyInfo ('N', ConsoleKey.N, false, false, false));
 
 
@@ -1584,7 +1584,7 @@ Y
 		public void LabelChangeText_RendersCorrectly_Constructors (int choice)
 		public void LabelChangeText_RendersCorrectly_Constructors (int choice)
 		{
 		{
 			var driver = new FakeDriver ();
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 
 			try {
 			try {
 				// Create a label with a short text 
 				// Create a label with a short text 
@@ -4117,5 +4117,64 @@ This is a tes
 			view.Enabled = false;
 			view.Enabled = false;
 			Assert.Equal (view.ColorScheme.Disabled, view.GetHotNormalColor ());
 			Assert.Equal (view.ColorScheme.Disabled, view.GetHotNormalColor ());
 		}
 		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData (true)]
+		[InlineData (false)]
+		public void Clear_Does_Not_Spillover_Its_Parent (bool label)
+		{
+			var root = new View () { Width = 20, Height = 10 };
+
+			var v = label == true ?
+				new Label (new string ('c', 100)) {
+					Width = Dim.Fill ()
+				} :
+				(View)new TextView () {
+					Height = 1,
+					Text = new string ('c', 100),
+					Width = Dim.Fill ()
+				};
+
+			root.Add (v);
+
+			Application.Top.Add (root);
+			Application.Begin (Application.Top);
+
+			if (label) {
+				Assert.True (v.AutoSize);
+				Assert.False (v.CanFocus);
+				Assert.Equal (new Rect (0, 0, 100, 1), v.Frame);
+			} else {
+				Assert.False (v.AutoSize);
+				Assert.True (v.CanFocus);
+				Assert.Equal (new Rect (0, 0, 20, 1), v.Frame);
+			}
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+cccccccccccccccccccc", output);
+
+			var attributes = new Attribute [] {
+				Colors.TopLevel.Normal,
+				Colors.TopLevel.Focus,
+
+			};
+			if (label) {
+				TestHelpers.AssertDriverColorsAre (@"
+000000000000000000000", attributes);
+			} else {
+				TestHelpers.AssertDriverColorsAre (@"
+111111111111111111110", attributes);
+			}
+
+			if (label) {
+				root.CanFocus = true;
+				v.CanFocus = true;
+				Assert.False (v.HasFocus);
+				v.SetFocus ();
+				Application.Refresh ();
+				TestHelpers.AssertDriverColorsAre (@"
+111111111111111111110", attributes);
+			}
+		}
 	}
 	}
 }
 }