2
0

HotKeyTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. using System.Text;
  2. using Xunit.Abstractions;
  3. namespace ViewBaseTests;
  4. [Collection ("Global Test Setup")]
  5. public class HotKeyTests
  6. {
  7. [Theory]
  8. [InlineData (KeyCode.A)]
  9. [InlineData (KeyCode.A | KeyCode.ShiftMask)]
  10. [InlineData (KeyCode.D1)]
  11. [InlineData (KeyCode.D1 | KeyCode.ShiftMask)] // '!'
  12. [InlineData ((KeyCode)'х')] // Cyrillic x
  13. [InlineData ((KeyCode)'你')] // Chinese ni
  14. public void AddKeyBindingsForHotKey_Sets (KeyCode key)
  15. {
  16. var view = new View ();
  17. view.HotKey = KeyCode.Z;
  18. Assert.Equal (string.Empty, view.Title);
  19. Assert.Equal (KeyCode.Z, view.HotKey);
  20. view.AddKeyBindingsForHotKey (KeyCode.Null, key);
  21. // Verify key bindings were set
  22. // As passed
  23. Command [] commands = view.HotKeyBindings.GetCommands (key);
  24. Assert.Contains (Command.HotKey, commands);
  25. commands = view.HotKeyBindings.GetCommands (key | KeyCode.AltMask);
  26. Assert.Contains (Command.HotKey, commands);
  27. KeyCode baseKey = key & ~KeyCode.ShiftMask;
  28. // If A...Z, with and without shift
  29. if (baseKey is >= KeyCode.A and <= KeyCode.Z)
  30. {
  31. commands = view.HotKeyBindings.GetCommands (key | KeyCode.ShiftMask);
  32. Assert.Contains (Command.HotKey, commands);
  33. commands = view.HotKeyBindings.GetCommands (key & ~KeyCode.ShiftMask);
  34. Assert.Contains (Command.HotKey, commands);
  35. commands = view.HotKeyBindings.GetCommands (key | KeyCode.AltMask);
  36. Assert.Contains (Command.HotKey, commands);
  37. commands = view.HotKeyBindings.GetCommands ((key & ~KeyCode.ShiftMask) | KeyCode.AltMask);
  38. Assert.Contains (Command.HotKey, commands);
  39. }
  40. else
  41. {
  42. // Non A..Z keys should not have shift bindings
  43. if (key.HasFlag (KeyCode.ShiftMask))
  44. {
  45. commands = view.HotKeyBindings.GetCommands (key & ~KeyCode.ShiftMask);
  46. Assert.Empty (commands);
  47. }
  48. else
  49. {
  50. commands = view.HotKeyBindings.GetCommands (key | KeyCode.ShiftMask);
  51. Assert.Empty (commands);
  52. }
  53. }
  54. }
  55. [Fact]
  56. public void AddKeyBindingsForHotKey_SetsBinding_Key ()
  57. {
  58. var view = new View ();
  59. view.HotKey = KeyCode.Z;
  60. Assert.Equal (string.Empty, view.Title);
  61. Assert.Equal (KeyCode.Z, view.HotKey);
  62. view.AddKeyBindingsForHotKey (view.HotKey, Key.A);
  63. view.HotKeyBindings.TryGet (Key.A, out var binding);
  64. Assert.Equal (Key.A, binding.Key);
  65. }
  66. [Fact]
  67. public void AddKeyBindingsForHotKey_SetsBinding_Data ()
  68. {
  69. var view = new View ();
  70. view.HotKey = KeyCode.Z;
  71. Assert.Equal (KeyCode.Z, view.HotKey);
  72. view.AddKeyBindingsForHotKey (view.HotKey, Key.A, "data");
  73. view.HotKeyBindings.TryGet (Key.A, out var binding);
  74. Assert.Equal ("data", binding.Data);
  75. }
  76. [Fact]
  77. public void Defaults ()
  78. {
  79. var view = new View ();
  80. Assert.Equal (string.Empty, view.Title);
  81. Assert.Equal (KeyCode.Null, view.HotKey);
  82. // Verify key bindings were set
  83. Command [] commands = view.KeyBindings.GetCommands (KeyCode.Null);
  84. Assert.Empty (commands);
  85. commands = view.HotKeyBindings.GetCommands (KeyCode.Null);
  86. Assert.Empty (commands);
  87. Assert.Empty (view.HotKeyBindings.GetBindings ());
  88. }
  89. [Theory]
  90. [InlineData (KeyCode.Null, true)] // non-shift
  91. [InlineData (KeyCode.ShiftMask, true)]
  92. [InlineData (KeyCode.AltMask, true)]
  93. [InlineData (KeyCode.ShiftMask | KeyCode.AltMask, true)]
  94. [InlineData (KeyCode.CtrlMask, false)]
  95. [InlineData (KeyCode.ShiftMask | KeyCode.CtrlMask, false)]
  96. public void NewKeyDownEvent_Runs_Default_HotKey_Command (KeyCode mask, bool expected)
  97. {
  98. var view = new View { HotKeySpecifier = (Rune)'^', Title = "^Test" };
  99. view.CanFocus = true;
  100. Assert.False (view.HasFocus);
  101. view.NewKeyDownEvent (KeyCode.T | mask);
  102. Assert.Equal (expected, view.HasFocus);
  103. }
  104. [Fact]
  105. public void NewKeyDownEvent_Ignores_Focus_KeyBindings_SuperView ()
  106. {
  107. var view = new View ();
  108. view.HotKeyBindings.Add (Key.A, Command.HotKey);
  109. view.KeyDownNotHandled += (s, e) => { Assert.Fail (); };
  110. var superView = new View ();
  111. superView.Add (view);
  112. var ke = Key.A;
  113. superView.NewKeyDownEvent (ke);
  114. }
  115. [Fact]
  116. public void NewKeyDownEvent_Honors_HotKey_KeyBindings_SuperView ()
  117. {
  118. var view = new View ();
  119. view.HotKeyBindings.Add (Key.A, Command.HotKey);
  120. bool hotKeyInvoked = false;
  121. view.HandlingHotKey += (s, e) => { hotKeyInvoked = true; };
  122. bool notHandled = false;
  123. view.KeyDownNotHandled += (s, e) => { notHandled = true; };
  124. var superView = new View ();
  125. superView.Add (view);
  126. var ke = Key.A;
  127. superView.NewKeyDownEvent (ke);
  128. Assert.False (notHandled);
  129. Assert.True (hotKeyInvoked);
  130. }
  131. [Fact]
  132. public void NewKeyDownEvent_InNewKeyDownEvent_Invokes_HotKey_Command_With_SuperView ()
  133. {
  134. var superView = new View ()
  135. {
  136. CanFocus = true
  137. };
  138. var view1 = new View
  139. {
  140. HotKeySpecifier = (Rune)'^',
  141. Title = "view^1",
  142. CanFocus = true
  143. };
  144. var view2 = new View
  145. {
  146. HotKeySpecifier = (Rune)'^',
  147. Title = "view^2",
  148. CanFocus = true
  149. };
  150. superView.Add (view1, view2);
  151. superView.SetFocus ();
  152. Assert.True (view1.HasFocus);
  153. var ke = Key.D2;
  154. superView.NewKeyDownEvent (ke);
  155. Assert.True (view2.HasFocus);
  156. }
  157. [Fact]
  158. public void Set_RemovesOldKeyBindings ()
  159. {
  160. var view = new View ();
  161. view.HotKey = KeyCode.A;
  162. Assert.Equal (string.Empty, view.Title);
  163. Assert.Equal (KeyCode.A, view.HotKey);
  164. // Verify key bindings were set
  165. Command [] commands = view.HotKeyBindings.GetCommands (KeyCode.A);
  166. Assert.Contains (Command.HotKey, commands);
  167. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.ShiftMask);
  168. Assert.Contains (Command.HotKey, commands);
  169. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.AltMask);
  170. Assert.Contains (Command.HotKey, commands);
  171. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.ShiftMask | KeyCode.AltMask);
  172. Assert.Contains (Command.HotKey, commands);
  173. // Now set again
  174. view.HotKey = KeyCode.B;
  175. Assert.Equal (string.Empty, view.Title);
  176. Assert.Equal (KeyCode.B, view.HotKey);
  177. commands = view.HotKeyBindings.GetCommands (KeyCode.A);
  178. Assert.DoesNotContain (Command.HotKey, commands);
  179. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.ShiftMask);
  180. Assert.DoesNotContain (Command.HotKey, commands);
  181. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.AltMask);
  182. Assert.DoesNotContain (Command.HotKey, commands);
  183. commands = view.HotKeyBindings.GetCommands (KeyCode.A | KeyCode.ShiftMask | KeyCode.AltMask);
  184. Assert.DoesNotContain (Command.HotKey, commands);
  185. }
  186. [Theory]
  187. [InlineData (KeyCode.A)]
  188. [InlineData (KeyCode.A | KeyCode.ShiftMask)]
  189. [InlineData (KeyCode.D1)]
  190. [InlineData (KeyCode.D1 | KeyCode.ShiftMask)]
  191. [InlineData ((KeyCode)'!')]
  192. [InlineData ((KeyCode)'х')] // Cyrillic x
  193. [InlineData ((KeyCode)'你')] // Chinese ni
  194. [InlineData ((KeyCode)'ö')] // German o umlaut
  195. [InlineData (KeyCode.Null)]
  196. public void Set_Sets_WithValidKey (KeyCode key)
  197. {
  198. var view = new View ();
  199. view.HotKey = key;
  200. Assert.Equal (key, view.HotKey);
  201. }
  202. [Theory]
  203. [InlineData (KeyCode.A)]
  204. [InlineData (KeyCode.A | KeyCode.ShiftMask)]
  205. [InlineData (KeyCode.D1)]
  206. [InlineData (KeyCode.D1 | KeyCode.ShiftMask)] // '!'
  207. [InlineData ((KeyCode)'х')] // Cyrillic x
  208. [InlineData ((KeyCode)'你')] // Chinese ni
  209. [InlineData ((KeyCode)'ö')] // German o umlaut
  210. public void Set_SetsKeyBindings (KeyCode key)
  211. {
  212. var view = new View ();
  213. view.HotKey = key;
  214. Assert.Equal (string.Empty, view.Title);
  215. Assert.Equal (key, view.HotKey);
  216. // Verify key bindings were set
  217. // As passed
  218. Command [] commands = view.HotKeyBindings.GetCommands (view.HotKey);
  219. Assert.Contains (Command.HotKey, commands);
  220. Key baseKey = view.HotKey.NoShift;
  221. // If A...Z, with and without shift
  222. if (baseKey.IsKeyCodeAtoZ)
  223. {
  224. commands = view.HotKeyBindings.GetCommands (view.HotKey.WithShift);
  225. Assert.Contains (Command.HotKey, commands);
  226. commands = view.HotKeyBindings.GetCommands (view.HotKey.NoShift);
  227. Assert.Contains (Command.HotKey, commands);
  228. commands = view.HotKeyBindings.GetCommands (view.HotKey.WithAlt);
  229. Assert.Contains (Command.HotKey, commands);
  230. commands = view.HotKeyBindings.GetCommands (view.HotKey.NoShift.WithAlt);
  231. Assert.Contains (Command.HotKey, commands);
  232. }
  233. else
  234. {
  235. // Non A..Z keys should not have shift bindings
  236. if (view.HotKey.IsShift)
  237. {
  238. commands = view.HotKeyBindings.GetCommands (view.HotKey.NoShift);
  239. Assert.Empty (commands);
  240. }
  241. else
  242. {
  243. commands = view.HotKeyBindings.GetCommands (view.HotKey.WithShift);
  244. Assert.Empty (commands);
  245. }
  246. }
  247. }
  248. [Fact]
  249. public void Set_Throws_If_Modifiers_Are_Included ()
  250. {
  251. var view = new View ();
  252. // A..Z must be naked (Alt is assumed)
  253. view.HotKey = Key.A.WithAlt;
  254. Assert.Throws<ArgumentException> (() => view.HotKey = Key.A.WithCtrl);
  255. Assert.Throws<ArgumentException> (
  256. () =>
  257. view.HotKey =
  258. KeyCode.A | KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.CtrlMask
  259. );
  260. // All others must not have Ctrl (Alt is assumed)
  261. view.HotKey = Key.D1.WithAlt;
  262. Assert.Throws<ArgumentException> (() => view.HotKey = Key.D1.WithCtrl);
  263. Assert.Throws<ArgumentException> (
  264. () =>
  265. view.HotKey =
  266. KeyCode.D1 | KeyCode.ShiftMask | KeyCode.AltMask | KeyCode.CtrlMask
  267. );
  268. // Shift is ok (e.g. this is '!')
  269. view.HotKey = Key.D1.WithShift;
  270. }
  271. [Theory]
  272. [InlineData (KeyCode.Delete)]
  273. [InlineData (KeyCode.Backspace)]
  274. [InlineData (KeyCode.Tab)]
  275. [InlineData (KeyCode.Enter)]
  276. [InlineData (KeyCode.Esc)]
  277. [InlineData (KeyCode.Space)]
  278. [InlineData (KeyCode.CursorLeft)]
  279. [InlineData (KeyCode.F1)]
  280. [InlineData (KeyCode.Null | KeyCode.ShiftMask)]
  281. public void Set_Throws_With_Invalid_Key (KeyCode key)
  282. {
  283. var view = new View ();
  284. Assert.Throws<ArgumentException> (() => view.HotKey = key);
  285. }
  286. [Theory]
  287. [InlineData ("Test", KeyCode.Null)]
  288. [InlineData ("^Test", KeyCode.T)]
  289. [InlineData ("T^est", KeyCode.E)]
  290. [InlineData ("Te^st", KeyCode.S)]
  291. [InlineData ("Tes^t", KeyCode.T)]
  292. [InlineData ("other", KeyCode.Null)]
  293. [InlineData ("oTher", KeyCode.Null)]
  294. [InlineData ("^Öther", (KeyCode)'Ö')]
  295. [InlineData ("^öther", (KeyCode)'ö')]
  296. // BUGBUG: '!' should be supported. Line 968 of TextFormatter filters on char.IsLetterOrDigit
  297. //[InlineData ("Test^!", (Key)'!')]
  298. public void Title_Change_Sets_HotKey (string title, KeyCode expectedHotKey)
  299. {
  300. var view = new View { HotKeySpecifier = new Rune ('^'), Title = "^Hello" };
  301. Assert.Equal (KeyCode.H, view.HotKey);
  302. view.Title = title;
  303. Assert.Equal (expectedHotKey, view.HotKey);
  304. }
  305. [Theory]
  306. [InlineData ("^Test")]
  307. public void Title_Empty_Sets_HotKey_To_Null (string title)
  308. {
  309. var view = new View { HotKeySpecifier = (Rune)'^', Title = title };
  310. Assert.Equal (title, view.Title);
  311. Assert.Equal (KeyCode.T, view.HotKey);
  312. view.Title = string.Empty;
  313. Assert.Equal ("", view.Title);
  314. Assert.Equal (KeyCode.Null, view.HotKey);
  315. }
  316. }