|
@@ -1,15 +1,12 @@
|
|
-using UICatalog;
|
|
|
|
-using Xunit.Abstractions;
|
|
|
|
|
|
+using Xunit.Abstractions;
|
|
|
|
|
|
namespace Terminal.Gui.ApplicationTests;
|
|
namespace Terminal.Gui.ApplicationTests;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
-/// Application tests for keyboard support.
|
|
|
|
|
|
+/// Application tests for keyboard support.
|
|
/// </summary>
|
|
/// </summary>
|
|
public class KeyboardTests
|
|
public class KeyboardTests
|
|
{
|
|
{
|
|
- private readonly ITestOutputHelper _output;
|
|
|
|
-
|
|
|
|
public KeyboardTests (ITestOutputHelper output)
|
|
public KeyboardTests (ITestOutputHelper output)
|
|
{
|
|
{
|
|
_output = output;
|
|
_output = output;
|
|
@@ -19,247 +16,11 @@ public class KeyboardTests
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
- [Fact]
|
|
|
|
- [AutoInitShutdown]
|
|
|
|
- public void QuitKey_Getter_Setter ()
|
|
|
|
- {
|
|
|
|
- Toplevel top = new ();
|
|
|
|
- var isQuiting = false;
|
|
|
|
-
|
|
|
|
- top.Closing += (s, e) =>
|
|
|
|
- {
|
|
|
|
- isQuiting = true;
|
|
|
|
- e.Cancel = true;
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- Application.Begin (top);
|
|
|
|
- top.Running = true;
|
|
|
|
-
|
|
|
|
- Key prevKey = Application.QuitKey;
|
|
|
|
-
|
|
|
|
- Application.OnKeyDown (Application.QuitKey);
|
|
|
|
- Assert.True (isQuiting);
|
|
|
|
-
|
|
|
|
- isQuiting = false;
|
|
|
|
- Application.OnKeyDown (Application.QuitKey);
|
|
|
|
- Assert.True (isQuiting);
|
|
|
|
-
|
|
|
|
- isQuiting = false;
|
|
|
|
- Application.QuitKey = Key.C.WithCtrl;
|
|
|
|
- Application.OnKeyDown (prevKey); // Should not quit
|
|
|
|
- Assert.False (isQuiting);
|
|
|
|
- Application.OnKeyDown (Key.Q.WithCtrl);// Should not quit
|
|
|
|
- Assert.False (isQuiting);
|
|
|
|
-
|
|
|
|
- Application.OnKeyDown (Application.QuitKey);
|
|
|
|
- Assert.True (isQuiting);
|
|
|
|
-
|
|
|
|
- // Reset the QuitKey to avoid throws errors on another tests
|
|
|
|
- Application.QuitKey = prevKey;
|
|
|
|
- top.Dispose ();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- [Fact]
|
|
|
|
- public void QuitKey_Default_Is_Esc ()
|
|
|
|
- {
|
|
|
|
- Application.ResetState (true);
|
|
|
|
- // Before Init
|
|
|
|
- Assert.Equal (Key.Esc, Application.QuitKey);
|
|
|
|
-
|
|
|
|
- Application.Init (new FakeDriver ());
|
|
|
|
- // After Init
|
|
|
|
- Assert.Equal (Key.Esc, Application.QuitKey);
|
|
|
|
-
|
|
|
|
- Application.Shutdown ();
|
|
|
|
- }
|
|
|
|
|
|
+ private readonly ITestOutputHelper _output;
|
|
|
|
|
|
private object _timeoutLock;
|
|
private object _timeoutLock;
|
|
|
|
|
|
- [Fact]
|
|
|
|
- public void QuitKey_Quits ()
|
|
|
|
- {
|
|
|
|
- Assert.Null (_timeoutLock);
|
|
|
|
- _timeoutLock = new object ();
|
|
|
|
-
|
|
|
|
- uint abortTime = 500;
|
|
|
|
- bool initialized = false;
|
|
|
|
- int iteration = 0;
|
|
|
|
- bool shutdown = false;
|
|
|
|
- object timeout = null;
|
|
|
|
-
|
|
|
|
- Application.InitializedChanged += OnApplicationOnInitializedChanged;
|
|
|
|
-
|
|
|
|
- Application.Init (new FakeDriver ());
|
|
|
|
- Assert.True (initialized);
|
|
|
|
- Assert.False (shutdown);
|
|
|
|
-
|
|
|
|
- _output.WriteLine ("Application.Run<Toplevel> ().Dispose ()..");
|
|
|
|
- Application.Run<Toplevel> ().Dispose ();
|
|
|
|
- _output.WriteLine ("Back from Application.Run<Toplevel> ().Dispose ()");
|
|
|
|
-
|
|
|
|
- Assert.True (initialized);
|
|
|
|
- Assert.False (shutdown);
|
|
|
|
-
|
|
|
|
- Assert.Equal (1, iteration);
|
|
|
|
-
|
|
|
|
- Application.Shutdown ();
|
|
|
|
-
|
|
|
|
- Application.InitializedChanged -= OnApplicationOnInitializedChanged;
|
|
|
|
-
|
|
|
|
- lock (_timeoutLock)
|
|
|
|
- {
|
|
|
|
- if (timeout is { })
|
|
|
|
- {
|
|
|
|
- Application.RemoveTimeout (timeout);
|
|
|
|
- timeout = null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Assert.True (initialized);
|
|
|
|
- Assert.True (shutdown);
|
|
|
|
-
|
|
|
|
-#if DEBUG_IDISPOSABLE
|
|
|
|
- Assert.Empty (Responder.Instances);
|
|
|
|
-#endif
|
|
|
|
- lock (_timeoutLock)
|
|
|
|
- {
|
|
|
|
- _timeoutLock = null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
|
|
|
|
- {
|
|
|
|
- _output.WriteLine ("OnApplicationOnInitializedChanged: {0}", a.CurrentValue);
|
|
|
|
- if (a.CurrentValue)
|
|
|
|
- {
|
|
|
|
- Application.Iteration += OnApplicationOnIteration;
|
|
|
|
- initialized = true;
|
|
|
|
- lock (_timeoutLock)
|
|
|
|
- {
|
|
|
|
- timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- Application.Iteration -= OnApplicationOnIteration;
|
|
|
|
- shutdown = true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- bool ForceCloseCallback ()
|
|
|
|
- {
|
|
|
|
- lock (_timeoutLock)
|
|
|
|
- {
|
|
|
|
- _output.WriteLine ($"ForceCloseCallback. iteration: {iteration}");
|
|
|
|
- if (timeout is { })
|
|
|
|
- {
|
|
|
|
- timeout = null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- Application.ResetState (true);
|
|
|
|
- Assert.Fail ($"Failed to Quit with {Application.QuitKey} after {abortTime}ms. Force quit.");
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- void OnApplicationOnIteration (object s, IterationEventArgs a)
|
|
|
|
- {
|
|
|
|
- _output.WriteLine ("Iteration: {0}", iteration);
|
|
|
|
- iteration++;
|
|
|
|
- Assert.True (iteration < 2, "Too many iterations, something is wrong.");
|
|
|
|
- if (Application.IsInitialized)
|
|
|
|
- {
|
|
|
|
- _output.WriteLine (" Pressing QuitKey");
|
|
|
|
- Application.OnKeyDown (Application.QuitKey);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- [Fact (Skip = "Replace when new key statics are added.")]
|
|
|
|
- public void NextTabGroupKey_PrevTabGroupKey_Tests ()
|
|
|
|
- {
|
|
|
|
- Application.Init (new FakeDriver ());
|
|
|
|
-
|
|
|
|
- Toplevel top = new ();
|
|
|
|
- var w1 = new Window ();
|
|
|
|
- var v1 = new TextField ();
|
|
|
|
- var v2 = new TextView ();
|
|
|
|
- w1.Add (v1, v2);
|
|
|
|
-
|
|
|
|
- var w2 = new Window ();
|
|
|
|
- var v3 = new CheckBox ();
|
|
|
|
- var v4 = new Button ();
|
|
|
|
- w2.Add (v3, v4);
|
|
|
|
-
|
|
|
|
- top.Add (w1, w2);
|
|
|
|
-
|
|
|
|
- Application.Iteration += (s, a) =>
|
|
|
|
- {
|
|
|
|
- Assert.True (v1.HasFocus);
|
|
|
|
-
|
|
|
|
- // Using default keys.
|
|
|
|
- Application.OnKeyDown (Key.F6);
|
|
|
|
- Assert.True (v2.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6);
|
|
|
|
- Assert.True (v3.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6);
|
|
|
|
- Assert.True (v4.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6);
|
|
|
|
- Assert.True (v1.HasFocus);
|
|
|
|
-
|
|
|
|
- Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
- Assert.True (v4.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
- Assert.True (v3.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
- Assert.True (v2.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
- Assert.True (v1.HasFocus);
|
|
|
|
-
|
|
|
|
- // Using alternate keys.
|
|
|
|
- Application.NextTabGroupKey = Key.F7;
|
|
|
|
- Application.PrevTabGroupKey = Key.F8;
|
|
|
|
-
|
|
|
|
- Application.OnKeyDown (Key.F7);
|
|
|
|
- Assert.True (v2.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F7);
|
|
|
|
- Assert.True (v3.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F7);
|
|
|
|
- Assert.True (v4.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F7);
|
|
|
|
- Assert.True (v1.HasFocus);
|
|
|
|
-
|
|
|
|
- Application.OnKeyDown (Key.F8);
|
|
|
|
- Assert.True (v4.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F8);
|
|
|
|
- Assert.True (v3.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F8);
|
|
|
|
- Assert.True (v2.HasFocus);
|
|
|
|
- Application.OnKeyDown (Key.F8);
|
|
|
|
- Assert.True (v1.HasFocus);
|
|
|
|
-
|
|
|
|
- Application.RequestStop ();
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- Application.Run (top);
|
|
|
|
-
|
|
|
|
- // Replacing the defaults keys to avoid errors on others unit tests that are using it.
|
|
|
|
- Application.NextTabGroupKey = Key.PageDown.WithCtrl;
|
|
|
|
- Application.PrevTabGroupKey = Key.PageUp.WithCtrl;
|
|
|
|
- Application.QuitKey = Key.Q.WithCtrl;
|
|
|
|
-
|
|
|
|
- Assert.Equal (KeyCode.PageDown | KeyCode.CtrlMask, Application.NextTabGroupKey.KeyCode);
|
|
|
|
- Assert.Equal (KeyCode.PageUp | KeyCode.CtrlMask, Application.PrevTabGroupKey.KeyCode);
|
|
|
|
- Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey.KeyCode);
|
|
|
|
-
|
|
|
|
- top.Dispose ();
|
|
|
|
- // Shutdown must be called to safely clean up Application if Init has been called
|
|
|
|
- Application.Shutdown ();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- [Fact]
|
|
|
|
|
|
+ [Fact (Skip = "No longer valid test.")]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
public void EnsuresTopOnFront_CanFocus_False_By_Keyboard ()
|
|
public void EnsuresTopOnFront_CanFocus_False_By_Keyboard ()
|
|
{
|
|
{
|
|
@@ -319,7 +80,7 @@ public class KeyboardTests
|
|
top.Dispose ();
|
|
top.Dispose ();
|
|
}
|
|
}
|
|
|
|
|
|
- [Fact]
|
|
|
|
|
|
+ [Fact (Skip = "No longer valid test.")]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
public void EnsuresTopOnFront_CanFocus_True_By_Keyboard ()
|
|
public void EnsuresTopOnFront_CanFocus_True_By_Keyboard ()
|
|
{
|
|
{
|
|
@@ -373,97 +134,29 @@ public class KeyboardTests
|
|
}
|
|
}
|
|
|
|
|
|
[Fact]
|
|
[Fact]
|
|
- public void KeyUp_Event ()
|
|
|
|
|
|
+ [AutoInitShutdown]
|
|
|
|
+ public void KeyBinding_Application_KeyBindings_Add_Adds ()
|
|
{
|
|
{
|
|
- Application.Init (new FakeDriver ());
|
|
|
|
-
|
|
|
|
- // Setup some fake keypresses (This)
|
|
|
|
- var input = "Tests";
|
|
|
|
|
|
+ Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
|
|
|
|
+ Application.KeyBindings.Add (Key.B, KeyBindingScope.Application, Command.Accept);
|
|
|
|
|
|
- Key originalQuitKey = Application.QuitKey;
|
|
|
|
- Application.QuitKey = Key.Q.WithCtrl;
|
|
|
|
- // Put a control-q in at the end
|
|
|
|
- FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo ('Q', ConsoleKey.Q, false, false, true));
|
|
|
|
|
|
+ Assert.True (Application.KeyBindings.TryGet (Key.A, out KeyBinding binding));
|
|
|
|
+ Assert.Null (binding.BoundView);
|
|
|
|
+ Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
|
|
|
|
+ Assert.Null (binding.BoundView);
|
|
|
|
+ }
|
|
|
|
|
|
- foreach (char c in input.Reverse ())
|
|
|
|
- {
|
|
|
|
- if (char.IsLetter (c))
|
|
|
|
- {
|
|
|
|
- FakeConsole.MockKeyPresses.Push (
|
|
|
|
- new ConsoleKeyInfo (
|
|
|
|
- c,
|
|
|
|
- (ConsoleKey)char.ToUpper (c),
|
|
|
|
- char.IsUpper (c),
|
|
|
|
- false,
|
|
|
|
- false
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- FakeConsole.MockKeyPresses.Push (
|
|
|
|
- new ConsoleKeyInfo (
|
|
|
|
- c,
|
|
|
|
- (ConsoleKey)c,
|
|
|
|
- false,
|
|
|
|
- false,
|
|
|
|
- false
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ [Fact]
|
|
|
|
+ [AutoInitShutdown]
|
|
|
|
+ public void KeyBinding_Application_RemoveKeyBinding_Removes ()
|
|
|
|
+ {
|
|
|
|
+ Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
|
|
|
|
|
|
- int stackSize = FakeConsole.MockKeyPresses.Count;
|
|
|
|
|
|
+ Assert.True (Application.KeyBindings.TryGet (Key.A, out _));
|
|
|
|
|
|
- var iterations = 0;
|
|
|
|
-
|
|
|
|
- Application.Iteration += (s, a) =>
|
|
|
|
- {
|
|
|
|
- iterations++;
|
|
|
|
-
|
|
|
|
- // Stop if we run out of control...
|
|
|
|
- if (iterations > 10)
|
|
|
|
- {
|
|
|
|
- Application.RequestStop ();
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- var keyUps = 0;
|
|
|
|
- var output = string.Empty;
|
|
|
|
- var top = new Toplevel ();
|
|
|
|
-
|
|
|
|
- top.KeyUp += (sender, args) =>
|
|
|
|
- {
|
|
|
|
- if (args.KeyCode != (KeyCode.CtrlMask | KeyCode.Q))
|
|
|
|
- {
|
|
|
|
- output += args.AsRune;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- keyUps++;
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- Application.Run (top);
|
|
|
|
- Application.QuitKey = originalQuitKey;
|
|
|
|
-
|
|
|
|
- // Input string should match output
|
|
|
|
- Assert.Equal (input, output);
|
|
|
|
-
|
|
|
|
- // # of key up events should match stack size
|
|
|
|
- //Assert.Equal (stackSize, keyUps);
|
|
|
|
- // We can't use numbers variables on the left side of an Assert.Equal/NotEqual,
|
|
|
|
- // it must be literal (Linux only).
|
|
|
|
- Assert.Equal (6, keyUps);
|
|
|
|
-
|
|
|
|
- // # of key up events should match # of iterations
|
|
|
|
- Assert.Equal (stackSize, iterations);
|
|
|
|
-
|
|
|
|
- top.Dispose ();
|
|
|
|
- Application.Shutdown ();
|
|
|
|
- Assert.Null (Application.Current);
|
|
|
|
- Assert.Null (Application.Top);
|
|
|
|
- Assert.Null (Application.MainLoop);
|
|
|
|
- Assert.Null (Application.Driver);
|
|
|
|
- }
|
|
|
|
|
|
+ Application.KeyBindings.Remove (Key.A);
|
|
|
|
+ Assert.False (Application.KeyBindings.TryGet (Key.A, out _));
|
|
|
|
+ }
|
|
|
|
|
|
[Fact]
|
|
[Fact]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
@@ -483,7 +176,7 @@ public class KeyboardTests
|
|
|
|
|
|
invoked = false;
|
|
invoked = false;
|
|
view.ApplicationCommand = false;
|
|
view.ApplicationCommand = false;
|
|
- Application.KeyBindings.Remove (KeyCode.A);
|
|
|
|
|
|
+ Application.KeyBindings.Remove (KeyCode.A);
|
|
Application.OnKeyDown (Key.A); // old
|
|
Application.OnKeyDown (Key.A); // old
|
|
Assert.False (invoked);
|
|
Assert.False (invoked);
|
|
Assert.False (view.ApplicationCommand);
|
|
Assert.False (view.ApplicationCommand);
|
|
@@ -538,19 +231,6 @@ public class KeyboardTests
|
|
top.Dispose ();
|
|
top.Dispose ();
|
|
}
|
|
}
|
|
|
|
|
|
- [Fact]
|
|
|
|
- [AutoInitShutdown]
|
|
|
|
- public void KeyBinding_Application_KeyBindings_Add_Adds ()
|
|
|
|
- {
|
|
|
|
- Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
|
|
|
|
- Application.KeyBindings.Add (Key.B, KeyBindingScope.Application, Command.Accept);
|
|
|
|
-
|
|
|
|
- Assert.True (Application.KeyBindings.TryGet (Key.A, out var binding));
|
|
|
|
- Assert.Null (binding.BoundView);
|
|
|
|
- Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
|
|
|
|
- Assert.Null (binding.BoundView);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
[Fact]
|
|
[Fact]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
public void KeyBinding_View_KeyBindings_Add_Adds ()
|
|
public void KeyBinding_View_KeyBindings_Add_Adds ()
|
|
@@ -561,7 +241,7 @@ public class KeyboardTests
|
|
View view2 = new ();
|
|
View view2 = new ();
|
|
Application.KeyBindings.Add (Key.B, view2, Command.Accept);
|
|
Application.KeyBindings.Add (Key.B, view2, Command.Accept);
|
|
|
|
|
|
- Assert.True (Application.KeyBindings.TryGet (Key.A, out var binding));
|
|
|
|
|
|
+ Assert.True (Application.KeyBindings.TryGet (Key.A, out KeyBinding binding));
|
|
Assert.Equal (view1, binding.BoundView);
|
|
Assert.Equal (view1, binding.BoundView);
|
|
Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
|
|
Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
|
|
Assert.Equal (view2, binding.BoundView);
|
|
Assert.Equal (view2, binding.BoundView);
|
|
@@ -569,29 +249,493 @@ public class KeyboardTests
|
|
|
|
|
|
[Fact]
|
|
[Fact]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
- public void KeyBinding_Application_RemoveKeyBinding_Removes ()
|
|
|
|
|
|
+ public void KeyBinding_View_KeyBindings_RemoveKeyBinding_Removes ()
|
|
{
|
|
{
|
|
- Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
|
|
|
|
|
|
+ View view1 = new ();
|
|
|
|
+ Application.KeyBindings.Add (Key.A, view1, Command.Accept);
|
|
|
|
|
|
- Assert.True (Application.KeyBindings.TryGet (Key.A, out _));
|
|
|
|
|
|
+ View view2 = new ();
|
|
|
|
+ Application.KeyBindings.Add (Key.B, view1, Command.Accept);
|
|
|
|
|
|
- Application.KeyBindings.Remove (Key.A);
|
|
|
|
|
|
+ Application.KeyBindings.Remove (Key.A, view1);
|
|
Assert.False (Application.KeyBindings.TryGet (Key.A, out _));
|
|
Assert.False (Application.KeyBindings.TryGet (Key.A, out _));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ [Fact]
|
|
|
|
+ public void KeyUp_Event ()
|
|
|
|
+ {
|
|
|
|
+ Application.Init (new FakeDriver ());
|
|
|
|
+
|
|
|
|
+ // Setup some fake keypresses (This)
|
|
|
|
+ var input = "Tests";
|
|
|
|
+
|
|
|
|
+ Key originalQuitKey = Application.QuitKey;
|
|
|
|
+ Application.QuitKey = Key.Q.WithCtrl;
|
|
|
|
+
|
|
|
|
+ // Put a control-q in at the end
|
|
|
|
+ FakeConsole.MockKeyPresses.Push (new ('Q', ConsoleKey.Q, false, false, true));
|
|
|
|
+
|
|
|
|
+ foreach (char c in input.Reverse ())
|
|
|
|
+ {
|
|
|
|
+ if (char.IsLetter (c))
|
|
|
|
+ {
|
|
|
|
+ FakeConsole.MockKeyPresses.Push (
|
|
|
|
+ new (
|
|
|
|
+ c,
|
|
|
|
+ (ConsoleKey)char.ToUpper (c),
|
|
|
|
+ char.IsUpper (c),
|
|
|
|
+ false,
|
|
|
|
+ false
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ FakeConsole.MockKeyPresses.Push (
|
|
|
|
+ new (
|
|
|
|
+ c,
|
|
|
|
+ (ConsoleKey)c,
|
|
|
|
+ false,
|
|
|
|
+ false,
|
|
|
|
+ false
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int stackSize = FakeConsole.MockKeyPresses.Count;
|
|
|
|
+
|
|
|
|
+ var iterations = 0;
|
|
|
|
+
|
|
|
|
+ Application.Iteration += (s, a) =>
|
|
|
|
+ {
|
|
|
|
+ iterations++;
|
|
|
|
+
|
|
|
|
+ // Stop if we run out of control...
|
|
|
|
+ if (iterations > 10)
|
|
|
|
+ {
|
|
|
|
+ Application.RequestStop ();
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var keyUps = 0;
|
|
|
|
+ var output = string.Empty;
|
|
|
|
+ var top = new Toplevel ();
|
|
|
|
+
|
|
|
|
+ top.KeyUp += (sender, args) =>
|
|
|
|
+ {
|
|
|
|
+ if (args.KeyCode != (KeyCode.CtrlMask | KeyCode.Q))
|
|
|
|
+ {
|
|
|
|
+ output += args.AsRune;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ keyUps++;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Application.Run (top);
|
|
|
|
+ Application.QuitKey = originalQuitKey;
|
|
|
|
+
|
|
|
|
+ // Input string should match output
|
|
|
|
+ Assert.Equal (input, output);
|
|
|
|
+
|
|
|
|
+ // # of key up events should match stack size
|
|
|
|
+ //Assert.Equal (stackSize, keyUps);
|
|
|
|
+ // We can't use numbers variables on the left side of an Assert.Equal/NotEqual,
|
|
|
|
+ // it must be literal (Linux only).
|
|
|
|
+ Assert.Equal (6, keyUps);
|
|
|
|
+
|
|
|
|
+ // # of key up events should match # of iterations
|
|
|
|
+ Assert.Equal (stackSize, iterations);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ Application.Shutdown ();
|
|
|
|
+ Assert.Null (Application.Current);
|
|
|
|
+ Assert.Null (Application.Top);
|
|
|
|
+ Assert.Null (Application.MainLoop);
|
|
|
|
+ Assert.Null (Application.Driver);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void NextTabGroupKey_Moves_Focus_To_TabStop_In_Next_TabGroup ()
|
|
|
|
+ {
|
|
|
|
+ // Arrange
|
|
|
|
+ Application.Navigation = new ();
|
|
|
|
+ var top = new Toplevel ();
|
|
|
|
+
|
|
|
|
+ var view1 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "view1",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabGroup
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var subView1 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "subView1",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabStop
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ view1.Add (subView1);
|
|
|
|
+
|
|
|
|
+ var view2 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "view2",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabGroup
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var subView2 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "subView2",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabStop
|
|
|
|
+ };
|
|
|
|
+ view2.Add (subView2);
|
|
|
|
+
|
|
|
|
+ top.Add (view1, view2);
|
|
|
|
+ Application.Top = top;
|
|
|
|
+ Application.Current = top;
|
|
|
|
+ view1.SetFocus ();
|
|
|
|
+ Assert.True (view1.HasFocus);
|
|
|
|
+ Assert.True (subView1.HasFocus);
|
|
|
|
+
|
|
|
|
+ // Act
|
|
|
|
+ Application.OnKeyDown (Application.NextTabGroupKey);
|
|
|
|
+
|
|
|
|
+ // Assert
|
|
|
|
+ Assert.True (view2.HasFocus);
|
|
|
|
+ Assert.True (subView2.HasFocus);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ Application.Navigation = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void NextTabGroupKey_PrevTabGroupKey_Tests ()
|
|
|
|
+ {
|
|
|
|
+ Application.Init (new FakeDriver ());
|
|
|
|
+
|
|
|
|
+ Toplevel top = new (); // TabGroup
|
|
|
|
+ var w1 = new Window (); // TabGroup
|
|
|
|
+ var v1 = new TextField (); // TabStop
|
|
|
|
+ var v2 = new TextView (); // TabStop
|
|
|
|
+ w1.Add (v1, v2);
|
|
|
|
+
|
|
|
|
+ var w2 = new Window (); // TabGroup
|
|
|
|
+ var v3 = new CheckBox (); // TabStop
|
|
|
|
+ var v4 = new Button (); // TabStop
|
|
|
|
+ w2.Add (v3, v4);
|
|
|
|
+
|
|
|
|
+ top.Add (w1, w2);
|
|
|
|
+
|
|
|
|
+ Application.Iteration += (s, a) =>
|
|
|
|
+ {
|
|
|
|
+ Assert.True (v1.HasFocus);
|
|
|
|
+
|
|
|
|
+ // Across TabGroups
|
|
|
|
+ Application.OnKeyDown (Key.F6);
|
|
|
|
+ Assert.True (v3.HasFocus);
|
|
|
|
+ Application.OnKeyDown (Key.F6);
|
|
|
|
+ Assert.True (v1.HasFocus);
|
|
|
|
+
|
|
|
|
+ Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
+ Assert.True (v3.HasFocus);
|
|
|
|
+ Application.OnKeyDown (Key.F6.WithShift);
|
|
|
|
+ Assert.True (v1.HasFocus);
|
|
|
|
+
|
|
|
|
+ // Restore?
|
|
|
|
+ Application.OnKeyDown (Key.Tab);
|
|
|
|
+ Assert.True (v2.HasFocus);
|
|
|
|
+
|
|
|
|
+ Application.OnKeyDown (Key.F6);
|
|
|
|
+ Assert.True (v3.HasFocus);
|
|
|
|
+
|
|
|
|
+ Application.OnKeyDown (Key.F6);
|
|
|
|
+ Assert.True (v2.HasFocus);
|
|
|
|
+
|
|
|
|
+ Application.RequestStop ();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Application.Run (top);
|
|
|
|
+
|
|
|
|
+ // Replacing the defaults keys to avoid errors on others unit tests that are using it.
|
|
|
|
+ Application.NextTabGroupKey = Key.PageDown.WithCtrl;
|
|
|
|
+ Application.PrevTabGroupKey = Key.PageUp.WithCtrl;
|
|
|
|
+ Application.QuitKey = Key.Q.WithCtrl;
|
|
|
|
+
|
|
|
|
+ Assert.Equal (KeyCode.PageDown | KeyCode.CtrlMask, Application.NextTabGroupKey.KeyCode);
|
|
|
|
+ Assert.Equal (KeyCode.PageUp | KeyCode.CtrlMask, Application.PrevTabGroupKey.KeyCode);
|
|
|
|
+ Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey.KeyCode);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+
|
|
|
|
+ // Shutdown must be called to safely clean up Application if Init has been called
|
|
|
|
+ Application.Shutdown ();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void NextTabKey_Moves_Focus_To_Next_TabStop ()
|
|
|
|
+ {
|
|
|
|
+ // Arrange
|
|
|
|
+ Application.Navigation = new ();
|
|
|
|
+ var top = new Toplevel ();
|
|
|
|
+ var view1 = new View { Id = "view1", CanFocus = true };
|
|
|
|
+ var view2 = new View { Id = "view2", CanFocus = true };
|
|
|
|
+ top.Add (view1, view2);
|
|
|
|
+ Application.Top = top;
|
|
|
|
+ Application.Current = top;
|
|
|
|
+ view1.SetFocus ();
|
|
|
|
+
|
|
|
|
+ // Act
|
|
|
|
+ Application.OnKeyDown (Application.NextTabKey);
|
|
|
|
+
|
|
|
|
+ // Assert
|
|
|
|
+ Assert.True (view2.HasFocus);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ Application.Navigation = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void PrevTabGroupKey_Moves_Focus_To_TabStop_In_Prev_TabGroup ()
|
|
|
|
+ {
|
|
|
|
+ // Arrange
|
|
|
|
+ Application.Navigation = new ();
|
|
|
|
+ var top = new Toplevel ();
|
|
|
|
+
|
|
|
|
+ var view1 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "view1",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabGroup
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var subView1 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "subView1",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabStop
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ view1.Add (subView1);
|
|
|
|
+
|
|
|
|
+ var view2 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "view2",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabGroup
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var subView2 = new View
|
|
|
|
+ {
|
|
|
|
+ Id = "subView2",
|
|
|
|
+ CanFocus = true,
|
|
|
|
+ TabStop = TabBehavior.TabStop
|
|
|
|
+ };
|
|
|
|
+ view2.Add (subView2);
|
|
|
|
+
|
|
|
|
+ top.Add (view1, view2);
|
|
|
|
+ Application.Top = top;
|
|
|
|
+ Application.Current = top;
|
|
|
|
+ view1.SetFocus ();
|
|
|
|
+ Assert.True (view1.HasFocus);
|
|
|
|
+ Assert.True (subView1.HasFocus);
|
|
|
|
+
|
|
|
|
+ // Act
|
|
|
|
+ Application.OnKeyDown (Application.PrevTabGroupKey);
|
|
|
|
+
|
|
|
|
+ // Assert
|
|
|
|
+ Assert.True (view2.HasFocus);
|
|
|
|
+ Assert.True (subView2.HasFocus);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ Application.Navigation = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void PrevTabKey_Moves_Focus_To_Prev_TabStop ()
|
|
|
|
+ {
|
|
|
|
+ // Arrange
|
|
|
|
+ Application.Navigation = new ();
|
|
|
|
+ var top = new Toplevel ();
|
|
|
|
+ var view1 = new View { Id = "view1", CanFocus = true };
|
|
|
|
+ var view2 = new View { Id = "view2", CanFocus = true };
|
|
|
|
+ top.Add (view1, view2);
|
|
|
|
+ Application.Top = top;
|
|
|
|
+ Application.Current = top;
|
|
|
|
+ view1.SetFocus ();
|
|
|
|
+
|
|
|
|
+ // Act
|
|
|
|
+ Application.OnKeyDown (Application.NextTabKey);
|
|
|
|
+
|
|
|
|
+ // Assert
|
|
|
|
+ Assert.True (view2.HasFocus);
|
|
|
|
+
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ Application.Navigation = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void QuitKey_Default_Is_Esc ()
|
|
|
|
+ {
|
|
|
|
+ Application.ResetState (true);
|
|
|
|
+
|
|
|
|
+ // Before Init
|
|
|
|
+ Assert.Equal (Key.Esc, Application.QuitKey);
|
|
|
|
+
|
|
|
|
+ Application.Init (new FakeDriver ());
|
|
|
|
+
|
|
|
|
+ // After Init
|
|
|
|
+ Assert.Equal (Key.Esc, Application.QuitKey);
|
|
|
|
+
|
|
|
|
+ Application.Shutdown ();
|
|
|
|
+ }
|
|
|
|
+
|
|
[Fact]
|
|
[Fact]
|
|
[AutoInitShutdown]
|
|
[AutoInitShutdown]
|
|
- public void KeyBinding_View_KeyBindings_RemoveKeyBinding_Removes ()
|
|
|
|
|
|
+ public void QuitKey_Getter_Setter ()
|
|
{
|
|
{
|
|
|
|
+ Toplevel top = new ();
|
|
|
|
+ var isQuiting = false;
|
|
|
|
|
|
- View view1 = new ();
|
|
|
|
- Application.KeyBindings.Add (Key.A, view1, Command.Accept);
|
|
|
|
|
|
+ top.Closing += (s, e) =>
|
|
|
|
+ {
|
|
|
|
+ isQuiting = true;
|
|
|
|
+ e.Cancel = true;
|
|
|
|
+ };
|
|
|
|
|
|
- View view2 = new ();
|
|
|
|
- Application.KeyBindings.Add (Key.B, view1, Command.Accept);
|
|
|
|
|
|
+ Application.Begin (top);
|
|
|
|
+ top.Running = true;
|
|
|
|
|
|
- Application.KeyBindings.Remove (Key.A, view1);
|
|
|
|
- Assert.False (Application.KeyBindings.TryGet (Key.A, out _));
|
|
|
|
|
|
+ Key prevKey = Application.QuitKey;
|
|
|
|
+
|
|
|
|
+ Application.OnKeyDown (Application.QuitKey);
|
|
|
|
+ Assert.True (isQuiting);
|
|
|
|
+
|
|
|
|
+ isQuiting = false;
|
|
|
|
+ Application.OnKeyDown (Application.QuitKey);
|
|
|
|
+ Assert.True (isQuiting);
|
|
|
|
+
|
|
|
|
+ isQuiting = false;
|
|
|
|
+ Application.QuitKey = Key.C.WithCtrl;
|
|
|
|
+ Application.OnKeyDown (prevKey); // Should not quit
|
|
|
|
+ Assert.False (isQuiting);
|
|
|
|
+ Application.OnKeyDown (Key.Q.WithCtrl); // Should not quit
|
|
|
|
+ Assert.False (isQuiting);
|
|
|
|
+
|
|
|
|
+ Application.OnKeyDown (Application.QuitKey);
|
|
|
|
+ Assert.True (isQuiting);
|
|
|
|
+
|
|
|
|
+ // Reset the QuitKey to avoid throws errors on another tests
|
|
|
|
+ Application.QuitKey = prevKey;
|
|
|
|
+ top.Dispose ();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Fact]
|
|
|
|
+ public void QuitKey_Quits ()
|
|
|
|
+ {
|
|
|
|
+ Assert.Null (_timeoutLock);
|
|
|
|
+ _timeoutLock = new ();
|
|
|
|
+
|
|
|
|
+ uint abortTime = 500;
|
|
|
|
+ var initialized = false;
|
|
|
|
+ var iteration = 0;
|
|
|
|
+ var shutdown = false;
|
|
|
|
+ object timeout = null;
|
|
|
|
+
|
|
|
|
+ Application.InitializedChanged += OnApplicationOnInitializedChanged;
|
|
|
|
+
|
|
|
|
+ Application.Init (new FakeDriver ());
|
|
|
|
+ Assert.True (initialized);
|
|
|
|
+ Assert.False (shutdown);
|
|
|
|
+
|
|
|
|
+ _output.WriteLine ("Application.Run<Toplevel> ().Dispose ()..");
|
|
|
|
+ Application.Run<Toplevel> ().Dispose ();
|
|
|
|
+ _output.WriteLine ("Back from Application.Run<Toplevel> ().Dispose ()");
|
|
|
|
+
|
|
|
|
+ Assert.True (initialized);
|
|
|
|
+ Assert.False (shutdown);
|
|
|
|
+
|
|
|
|
+ Assert.Equal (1, iteration);
|
|
|
|
+
|
|
|
|
+ Application.Shutdown ();
|
|
|
|
+
|
|
|
|
+ Application.InitializedChanged -= OnApplicationOnInitializedChanged;
|
|
|
|
+
|
|
|
|
+ lock (_timeoutLock)
|
|
|
|
+ {
|
|
|
|
+ if (timeout is { })
|
|
|
|
+ {
|
|
|
|
+ Application.RemoveTimeout (timeout);
|
|
|
|
+ timeout = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Assert.True (initialized);
|
|
|
|
+ Assert.True (shutdown);
|
|
|
|
+
|
|
|
|
+#if DEBUG_IDISPOSABLE
|
|
|
|
+ Assert.Empty (Responder.Instances);
|
|
|
|
+#endif
|
|
|
|
+ lock (_timeoutLock)
|
|
|
|
+ {
|
|
|
|
+ _timeoutLock = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
|
|
|
|
+ {
|
|
|
|
+ _output.WriteLine ("OnApplicationOnInitializedChanged: {0}", a.CurrentValue);
|
|
|
|
+
|
|
|
|
+ if (a.CurrentValue)
|
|
|
|
+ {
|
|
|
|
+ Application.Iteration += OnApplicationOnIteration;
|
|
|
|
+ initialized = true;
|
|
|
|
+
|
|
|
|
+ lock (_timeoutLock)
|
|
|
|
+ {
|
|
|
|
+ timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ Application.Iteration -= OnApplicationOnIteration;
|
|
|
|
+ shutdown = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool ForceCloseCallback ()
|
|
|
|
+ {
|
|
|
|
+ lock (_timeoutLock)
|
|
|
|
+ {
|
|
|
|
+ _output.WriteLine ($"ForceCloseCallback. iteration: {iteration}");
|
|
|
|
+
|
|
|
|
+ if (timeout is { })
|
|
|
|
+ {
|
|
|
|
+ timeout = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Application.ResetState (true);
|
|
|
|
+ Assert.Fail ($"Failed to Quit with {Application.QuitKey} after {abortTime}ms. Force quit.");
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void OnApplicationOnIteration (object s, IterationEventArgs a)
|
|
|
|
+ {
|
|
|
|
+ _output.WriteLine ("Iteration: {0}", iteration);
|
|
|
|
+ iteration++;
|
|
|
|
+ Assert.True (iteration < 2, "Too many iterations, something is wrong.");
|
|
|
|
+
|
|
|
|
+ if (Application.IsInitialized)
|
|
|
|
+ {
|
|
|
|
+ _output.WriteLine (" Pressing QuitKey");
|
|
|
|
+ Application.OnKeyDown (Application.QuitKey);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// Test View for testing Application key Bindings
|
|
// Test View for testing Application key Bindings
|