Browse Source

Refactored AutoInitShutdown attribute - scary stuff

Charlie Kindel 2 years ago
parent
commit
1efb051379

+ 5 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -38,6 +38,11 @@ namespace Terminal.Gui {
 	/// can watch file descriptors using the AddWatch methods.
 	/// </remarks>
 	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);
 
 		[StructLayout (LayoutKind.Sequential)]

+ 32 - 7
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -6,10 +6,12 @@
 //
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Threading;
 using NStack;
+
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 
@@ -19,6 +21,26 @@ namespace Terminal.Gui {
 	/// </summary>
 	public class FakeDriver : ConsoleDriver {
 #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 FakeDriver.Behaviors ();
+
 		int cols, rows, left, top;
 		public override int Cols => cols;
 		public override int Rows => rows;
@@ -58,12 +80,11 @@ namespace Terminal.Gui {
 
 		static bool sync = false;
 		static public bool usingFakeClipboard;
-		
-		public FakeDriver (bool useFakeClipboard = true, bool fakeClipboardThrows = false)
+
+		public FakeDriver ()
 		{
-			usingFakeClipboard = useFakeClipboard;
-			if (usingFakeClipboard) {
-				clipboard = new FakeClipboard (fakeClipboardThrows);
+			if (FakeBehaviors.UseFakeClipboard) {
+				clipboard = new FakeClipboard (FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException, FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse);
 			} else {
 				if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
 					clipboard = new WindowsClipboard ();
@@ -650,13 +671,17 @@ namespace Terminal.Gui {
 		#endregion
 
 		public class FakeClipboard : ClipboardBase {
-			public override bool IsSupported => true;
 			public Exception FakeException = null;
 
 			string contents = string.Empty;
 
-			public FakeClipboard (bool fakeClipboardThrowsNotSupportedException = false)
+			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");
 				}

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

@@ -15,7 +15,7 @@ namespace Terminal.Gui {
 		AutoResetEvent waitForProbe = new AutoResetEvent (false);
 		ConsoleKeyInfo? keyResult = null;
 		MainLoop mainLoop;
-		Func<ConsoleKeyInfo> consoleKeyReaderFn = null;
+		Func<ConsoleKeyInfo> consoleKeyReaderFn = () => FakeConsole.ReadKey (true);
 
 		/// <summary>
 		/// Invoked when a Key is pressed.
@@ -23,18 +23,12 @@ namespace Terminal.Gui {
 		public Action<ConsoleKeyInfo> KeyPressed;
 
 		/// <summary>
-		/// Initializes the class.
+		/// Creates an instance of the FakeMainLoop. <paramref name="consoleDriver"/> is not used.
 		/// </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 ()

+ 30 - 14
Terminal.Gui/Core/Application.cs

@@ -375,14 +375,14 @@ namespace Terminal.Gui {
 				ResetState ();
 			}
 
-			// FakeDriver (for UnitTests)
+			// For UnitTests
 			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;
 			}
 
@@ -391,18 +391,34 @@ namespace Terminal.Gui {
 				if (ForceFakeConsole) {
 					// For Unit Testing only
 					Driver = new FakeDriver ();
-					mainLoopDriver = new FakeMainLoop (() => FakeConsole.ReadKey (true));
 				} else if (UseSystemConsole) {
 					Driver = new NetDriver ();
-					mainLoopDriver = new NetMainLoop (Driver);
 				} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
 					Driver = new WindowsDriver ();
-					mainLoopDriver = new WindowsMainLoop (Driver);
 				} else {
-					mainLoopDriver = new UnixMainLoop ();
 					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);
 
 			try {
@@ -414,7 +430,7 @@ namespace Terminal.Gui {
 				// In this case, we want to throw a more specific exception.
 				throw new InvalidOperationException ("Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", ex);
 			}
-			
+
 			SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
 
 			Top = topLevelFactory ();
@@ -901,7 +917,7 @@ namespace Terminal.Gui {
 			}
 
 			var rs = new RunState (toplevel);
-			
+
 			if (toplevel is ISupportInitializeNotification initializableNotification &&
 			    !initializableNotification.IsInitialized) {
 				initializableNotification.BeginInit ();
@@ -915,7 +931,7 @@ namespace Terminal.Gui {
 				// If Top was already initialized with Init, and Begin has never been called
 				// Top was not added to the toplevels Stack. It will thus never get disposed.
 				// Clean it up here:
-				if (Top != null && toplevel != Top && !toplevels.Contains(Top)) {
+				if (Top != null && toplevel != Top && !toplevels.Contains (Top)) {
 					Top.Dispose ();
 					Top = null;
 				}

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

@@ -102,7 +102,8 @@ namespace Terminal.Gui {
 		/// <summary>
 		///  Creates a new Mainloop. 
 		/// </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)
 		{
 			Driver = driver;

+ 2 - 2
UnitTests/AllViewsTests.cs

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

+ 10 - 10
UnitTests/ApplicationTests.cs

@@ -45,7 +45,7 @@ namespace Terminal.Gui.Core {
 
 		void Init ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (SynchronizationContext.Current);
@@ -62,7 +62,7 @@ namespace Terminal.Gui.Core {
 			// Verify initial state is per spec
 			Pre_Init_State ();
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			// Verify post-Init state is correct
 			Post_Init_State ();
@@ -87,7 +87,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void Init_Shutdown_Toplevel_Not_Disposed ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			Application.Shutdown ();
 
@@ -98,10 +98,10 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void Init_Unbalanced_Throwss ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			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 ();
 
 			Assert.Null (Application.Top);
@@ -110,9 +110,9 @@ namespace Terminal.Gui.Core {
 
 			// Now try the other way
 			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 ();
 
 			Assert.Null (Application.Top);
@@ -182,7 +182,7 @@ namespace Terminal.Gui.Core {
 			// NOTE: Run<T>, when called after Init has been called behaves differently than
 			// when called if Init has not been called.
 			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;
 			Action<Application.RunState> NewRunStateFn = (rs) => {
@@ -255,7 +255,7 @@ namespace Terminal.Gui.Core {
 			Init ();
 
 			// 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 ();
 
@@ -354,7 +354,7 @@ namespace Terminal.Gui.Core {
 			};
 
 			// 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 ();
 

+ 4 - 4
UnitTests/AttributeTests.cs

@@ -13,7 +13,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Constuctors_Constuct ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			// Test parameterless constructor
@@ -59,7 +59,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Implicit_Assign ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			var attr = new Attribute ();
@@ -100,7 +100,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Make_Creates ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			var fg = new Color ();
@@ -128,7 +128,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Get_Gets ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			var value = 42;

+ 56 - 2
UnitTests/ClipboardTests.cs

@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using Xunit;
 using Xunit.Abstractions;
+using static AutoInitShutdownAttribute;
 
 namespace Terminal.Gui.ConsoleDrivers {
 	public class ClipboardTests {
@@ -13,20 +14,37 @@ namespace Terminal.Gui.ConsoleDrivers {
 			this.output = output;
 		}
 
-		[Fact, AutoInitShutdown (useFakeClipboard: true, fakeClipboardThrowsNotSupportedException: true)]
+		[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, fakeClipboardThrowsNotSupportedException: true)]
+		[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 ()
 		{
@@ -44,6 +62,42 @@ namespace Terminal.Gui.ConsoleDrivers {
 			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 ()
 		{

+ 12 - 12
UnitTests/ConsoleDriverTests.cs

@@ -22,7 +22,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void Init_Inits ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			Assert.Equal (80, Console.BufferWidth);
@@ -41,7 +41,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void End_Cleans_Up ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			FakeConsole.ForegroundColor = ConsoleColor.Red;
@@ -67,7 +67,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void SetColors_Changes_Colors ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
 			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
@@ -90,7 +90,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		[Fact]
 		public void FakeDriver_Only_Sends_Keystrokes_Through_MockKeyPresses ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 			var view = new View ();
@@ -120,7 +120,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		[Fact]
 		public void FakeDriver_MockKeyPresses ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var text = "MockKeyPresses";
 			var mKeys = new Stack<ConsoleKeyInfo> ();
@@ -162,7 +162,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		[Fact]
 		public void SendKeys_Test ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 			var view = new View ();
@@ -260,7 +260,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void TerminalResized_Simulation ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			var wasTerminalResized = false;
 			Application.Resized = (e) => {
 				wasTerminalResized = true;
@@ -301,7 +301,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void HeightAsBuffer_Is_False_Left_And_Top_Is_Always_Zero ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			Assert.False (Application.HeightAsBuffer);
 			Assert.Equal (0, Console.WindowLeft);
@@ -318,7 +318,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
@@ -334,7 +334,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
@@ -373,7 +373,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);
@@ -389,7 +389,7 @@ namespace Terminal.Gui.ConsoleDrivers {
 		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			Application.HeightAsBuffer = true;
 			Assert.True (Application.HeightAsBuffer);

+ 10 - 10
UnitTests/DimTests.cs

@@ -252,7 +252,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -292,7 +292,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -313,7 +313,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -346,7 +346,7 @@ namespace Terminal.Gui.Core {
 		{
 			// 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;
 
@@ -541,7 +541,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void DimCombine_Do_Not_Throws ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var t = Application.Top;
 
@@ -588,7 +588,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void PosCombine_Will_Throws ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var t = Application.Top;
 
@@ -622,7 +622,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Add_Operator ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 
@@ -989,7 +989,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Add_Operator_With_Text ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 
@@ -1056,7 +1056,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Subtract_Operator ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 
@@ -1116,7 +1116,7 @@ namespace Terminal.Gui.Core {
 		public void Dim_Subtract_Operator_With_Text ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 

+ 2 - 2
UnitTests/GraphViewTests.cs

@@ -58,7 +58,7 @@ namespace Terminal.Gui.Views {
 		{
 			var driver = new FakeDriver ();
 			try {
-				Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (driver);
 			} catch (InvalidOperationException) {
 
 				// 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)
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 
 			// create a wide window

+ 23 - 18
UnitTests/MainLoopTests.cs

@@ -14,12 +14,17 @@ using Xunit.Sdk;
 using Console = Terminal.Gui.FakeConsole;
 
 namespace Terminal.Gui.Core {
+	/// <summary>
+	/// Tests MainLoop using the FakeMainLoop.
+	/// </summary>
 	public class MainLoopTests {
 
+		// TODO: Expand to test all the MainLoop implementations.
+
 		[Fact]
 		public void Constructor_Setups_Driver ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			Assert.NotNull (ml.Driver);
 		}
 
@@ -27,7 +32,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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> fnFalse = () => false;
@@ -81,7 +86,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void AddIdle_Function_GetsCalled_OnIteration ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 			var functionCalled = 0;
 			Func<bool> fn = () => {
@@ -97,7 +102,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void RemoveIdle_Function_NotCalled ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 			var functionCalled = 0;
 			Func<bool> fn = () => {
@@ -113,7 +118,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void AddThenRemoveIdle_Function_NotCalled ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 			var functionCalled = 0;
 			Func<bool> fn = () => {
@@ -130,7 +135,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void AddTwice_Function_CalledTwice ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 			var functionCalled = 0;
 			Func<bool> fn = () => {
@@ -161,7 +166,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 			Func<bool> fn1 = () => {
@@ -195,7 +200,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 			Func<bool> fn1 = () => {
@@ -227,7 +232,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 			Func<bool> fn = () => {
@@ -249,7 +254,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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 callbackCount = 0;
@@ -270,7 +275,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void AddTimer_Run_Called ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 			var ms = 100;
 
 			var callbackCount = 0;
@@ -290,7 +295,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 			object token1 = null, token2 = null;
 
@@ -322,7 +327,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 			object token1 = null, token2 = null;
 
@@ -359,7 +364,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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 watch = new System.Diagnostics.Stopwatch ();
 
@@ -385,7 +390,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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 watch = new System.Diagnostics.Stopwatch ();
 
@@ -413,7 +418,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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);
 
 			// Force stop if 10 iterations
@@ -442,7 +447,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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);
 
 			// Force stop if 10 iterations
@@ -475,7 +480,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void Invoke_Adds_Idle ()
 		{
-			var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			var ml = new MainLoop (new FakeMainLoop ());
 
 			var actionCalled = 0;
 			ml.Invoke (() => { actionCalled++; });

+ 2 - 2
UnitTests/MdiTests.cs

@@ -22,7 +22,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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 rs = Application.Begin (top);
@@ -38,7 +38,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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 rs = Application.Begin (mdi);

+ 8 - 8
UnitTests/PosTests.cs

@@ -555,7 +555,7 @@ namespace Terminal.Gui.Core {
 			// Setup Fake driver
 			(Window win, Button button) setup ()
 			{
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 				Application.Iteration = () => {
 					Application.RequestStop ();
 				};
@@ -700,7 +700,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -733,7 +733,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -755,7 +755,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -788,7 +788,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void PosCombine_Do_Not_Throws ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var t = Application.Top;
 
@@ -835,7 +835,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void PosCombine_Will_Throws ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var t = Application.Top;
 
@@ -868,7 +868,7 @@ namespace Terminal.Gui.Core {
 		public void Pos_Add_Operator ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 
@@ -917,7 +917,7 @@ namespace Terminal.Gui.Core {
 		public void Pos_Subtract_Operator ()
 		{
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var top = Application.Top;
 

+ 1 - 1
UnitTests/RunStateTests.cs

@@ -58,7 +58,7 @@ namespace Terminal.Gui.Core {
 
 		void Init ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (SynchronizationContext.Current);

+ 3 - 3
UnitTests/ScenarioTests.cs

@@ -61,7 +61,7 @@ namespace UICatalog {
 					return false;
 				};
 
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				// Close after a short period of time
 				var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), closeCallback);
@@ -97,7 +97,7 @@ namespace UICatalog {
 			// Passing empty string will cause just a ctrl-q to be fired
 			int stackSize = CreateInput ("");
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			int iterations = 0;
 			Application.Iteration = () => {
@@ -179,7 +179,7 @@ namespace UICatalog {
 			List<string> dimNames = new List<String> { "Factor", "Fill", "Absolute" };
 
 
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var Top = Application.Top;
 

+ 3 - 3
UnitTests/ScrollBarViewTests.cs

@@ -30,7 +30,7 @@ namespace Terminal.Gui.Views {
 					throw new InvalidOperationException ("After did not run.");
 				}
 
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				var top = Application.Top;
 
@@ -457,7 +457,7 @@ namespace Terminal.Gui.Views {
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_True_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		{
 			var exception = Record.Exception (() => {
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				var top = Application.Top;
 
@@ -527,7 +527,7 @@ namespace Terminal.Gui.Views {
 		public void Constructor_ShowBothScrollIndicator_False_And_IsVertical_False_Refresh_Does_Not_Throws_An_Object_Null_Exception ()
 		{
 			var exception = Record.Exception (() => {
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				var top = Application.Top;
 

+ 1 - 1
UnitTests/StatusBarTests.cs

@@ -37,7 +37,7 @@ namespace Terminal.Gui.Views {
 			Assert.Null (sb.Y);
 
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			sb = new StatusBar ();
 

+ 1 - 1
UnitTests/TabViewTests.cs

@@ -763,7 +763,7 @@ namespace Terminal.Gui.Views {
 		private void InitFakeDriver ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 		}
 	}

+ 33 - 11
UnitTests/TestHelpers.cs

@@ -21,21 +21,43 @@ using System.Diagnostics;
 // as a pair, and b) all unit test functions should be atomic..
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
 public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
+	// This defines the default behavior for the AutoInitShutdown attribute.
 
-	public AutoInitShutdownAttribute (bool autoInit = true, bool autoShutdown = true, bool useFakeClipboard = true, bool fakeClipboardThrowsNotSupportedException = false)
+	/// <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)
 	{
-		this.AutoInit = autoInit;
-		this.AutoShutdown = autoShutdown;
-		this.UseFakeClipboard = useFakeClipboard;
-		this.FakeClipboardThrowsNotSupportedException = fakeClipboardThrowsNotSupportedException;
+		//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;
-
-	public bool AutoInit { get; }
-	public bool AutoShutdown { get; }
-	public bool UseFakeClipboard { get; }
-	public bool FakeClipboardThrowsNotSupportedException { get; }
+	bool AutoInit { get; }
+	bool AutoShutdown { get;  }
+	Type DriverType;
 
 	public override void Before (MethodInfo methodUnderTest)
 	{
@@ -43,7 +65,7 @@ public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
 			throw new InvalidOperationException ("After did not run when AutoShutdown was specified.");
 		}
 		if (AutoInit) {
-			Application.Init (new FakeDriver (useFakeClipboard: UseFakeClipboard, fakeClipboardThrows: FakeClipboardThrowsNotSupportedException), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init ((ConsoleDriver)Activator.CreateInstance (DriverType));
 			_init = true;
 		}
 	}

+ 1 - 1
UnitTests/TextFieldTests.cs

@@ -15,7 +15,7 @@ namespace Terminal.Gui.Views {
 
 			public override void Before (MethodInfo methodUnderTest)
 			{
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				//                                                    1         2         3 
 				//                                          01234567890123456789012345678901=32 (Length)

+ 2 - 2
UnitTests/TextFormatterTests.cs

@@ -2968,7 +2968,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -3008,7 +3008,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 

+ 1 - 1
UnitTests/TextViewTests.cs

@@ -32,7 +32,7 @@ namespace Terminal.Gui.Views {
 					throw new InvalidOperationException ("After did not run.");
 				}
 
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+				Application.Init (new FakeDriver ());
 
 				//                   1         2         3 
 				//         01234567890123456789012345678901=32 (Length)

+ 1 - 1
UnitTests/ToplevelTests.cs

@@ -588,7 +588,7 @@ namespace Terminal.Gui.Core {
 
 			var win = new Window ();
 			win.Add (view);
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 			var top = Application.Top;
 			top.Add (win);
 

+ 1 - 1
UnitTests/TreeViewTests.cs

@@ -953,7 +953,7 @@ namespace Terminal.Gui.Views {
 		private void InitFakeDriver ()
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 			driver.Init (() => { });
 		}
 	}

+ 3 - 0
UnitTests/UnitTests.csproj

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

+ 10 - 10
UnitTests/ViewTests.cs

@@ -574,7 +574,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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", };
 
@@ -673,7 +673,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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", };
 
@@ -782,7 +782,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -819,7 +819,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -862,7 +862,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -897,7 +897,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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;
 
@@ -941,7 +941,7 @@ namespace Terminal.Gui.Core {
 		{
 			// 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 += () => {
 				Assert.Null (Application.Top.Focused);
@@ -959,7 +959,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		public void Multi_Thread_Toplevels ()
 		{
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (new FakeDriver ());
 
 			var t = Application.Top;
 			var w = new Window ();
@@ -1148,7 +1148,7 @@ namespace Terminal.Gui.Core {
 		[Fact]
 		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));
 
@@ -1584,7 +1584,7 @@ Y
 		public void LabelChangeText_RendersCorrectly_Constructors (int choice)
 		{
 			var driver = new FakeDriver ();
-			Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+			Application.Init (driver);
 
 			try {
 				// Create a label with a short text