ApplicationTests.cs 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Xunit;
  8. // Alias Console to MockConsole so we don't accidentally use Console
  9. using Console = Terminal.Gui.FakeConsole;
  10. namespace Terminal.Gui.ApplicationTests {
  11. public class ApplicationTests {
  12. public ApplicationTests ()
  13. {
  14. #if DEBUG_IDISPOSABLE
  15. Responder.Instances.Clear ();
  16. RunState.Instances.Clear ();
  17. #endif
  18. }
  19. void Pre_Init_State ()
  20. {
  21. Assert.Null (Application.Driver);
  22. Assert.Null (Application.Top);
  23. Assert.Null (Application.Current);
  24. Assert.Null (Application.MainLoop);
  25. Assert.Null (Application.Iteration);
  26. Assert.Null (Application.RootMouseEvent);
  27. Assert.Null (Application.TerminalResized);
  28. }
  29. void Post_Init_State ()
  30. {
  31. Assert.NotNull (Application.Driver);
  32. Assert.NotNull (Application.Top);
  33. Assert.NotNull (Application.Current);
  34. Assert.NotNull (Application.MainLoop);
  35. Assert.Null (Application.Iteration);
  36. Assert.Null (Application.RootMouseEvent);
  37. Assert.Null (Application.TerminalResized);
  38. // FakeDriver is always 80x25
  39. Assert.Equal (80, Application.Driver.Cols);
  40. Assert.Equal (25, Application.Driver.Rows);
  41. }
  42. void Init ()
  43. {
  44. Application.Init (new FakeDriver ());
  45. Assert.NotNull (Application.Driver);
  46. Assert.NotNull (Application.MainLoop);
  47. Assert.NotNull (SynchronizationContext.Current);
  48. }
  49. void Shutdown ()
  50. {
  51. Application.Shutdown ();
  52. }
  53. [Fact]
  54. public void Init_Shutdown_Cleans_Up ()
  55. {
  56. // Verify initial state is per spec
  57. //Pre_Init_State ();
  58. Application.Init (new FakeDriver ());
  59. // Verify post-Init state is correct
  60. //Post_Init_State ();
  61. Application.Shutdown ();
  62. // Verify state is back to initial
  63. //Pre_Init_State ();
  64. #if DEBUG_IDISPOSABLE
  65. // Validate there are no outstanding Responder-based instances
  66. // after a scenario was selected to run. This proves the main UI Catalog
  67. // 'app' closed cleanly.
  68. Assert.Empty (Responder.Instances);
  69. #endif
  70. }
  71. [Fact]
  72. public void Init_Unbalanced_Throws ()
  73. {
  74. Application.Init (new FakeDriver ());
  75. Toplevel topLevel = null;
  76. Assert.Throws<InvalidOperationException> (() => Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ()));
  77. Shutdown ();
  78. Assert.Null (Application.Top);
  79. Assert.Null (Application.MainLoop);
  80. Assert.Null (Application.Driver);
  81. // Now try the other way
  82. topLevel = null;
  83. Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
  84. Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver ()));
  85. Shutdown ();
  86. Assert.Null (Application.Top);
  87. Assert.Null (Application.MainLoop);
  88. Assert.Null (Application.Driver);
  89. }
  90. class TestToplevel : Toplevel {
  91. public TestToplevel ()
  92. {
  93. IsOverlappedContainer = false;
  94. }
  95. }
  96. [Fact]
  97. public void Init_Null_Driver_Should_Pick_A_Driver ()
  98. {
  99. Application.Init (null);
  100. Assert.NotNull (Application.Driver);
  101. Shutdown ();
  102. }
  103. [Fact]
  104. public void Init_Begin_End_Cleans_Up ()
  105. {
  106. Init ();
  107. // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
  108. // if we don't stop
  109. Application.Iteration = () => {
  110. Application.RequestStop ();
  111. };
  112. RunState runstate = null;
  113. EventHandler<RunStateEventArgs> NewRunStateFn = (s, e) => {
  114. Assert.NotNull (e.State);
  115. runstate = e.State;
  116. };
  117. Application.NotifyNewRunState += NewRunStateFn;
  118. Toplevel topLevel = new Toplevel ();
  119. var rs = Application.Begin (topLevel);
  120. Assert.NotNull (rs);
  121. Assert.NotNull (runstate);
  122. Assert.Equal (rs, runstate);
  123. Assert.Equal (topLevel, Application.Top);
  124. Assert.Equal (topLevel, Application.Current);
  125. Application.NotifyNewRunState -= NewRunStateFn;
  126. Application.End (runstate);
  127. Assert.Null (Application.Current);
  128. Assert.NotNull (Application.Top);
  129. Assert.NotNull (Application.MainLoop);
  130. Assert.NotNull (Application.Driver);
  131. Shutdown ();
  132. Assert.Null (Application.Top);
  133. Assert.Null (Application.MainLoop);
  134. Assert.Null (Application.Driver);
  135. }
  136. [Fact]
  137. public void InitWithTopLevelFactory_Begin_End_Cleans_Up ()
  138. {
  139. // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
  140. // if we don't stop
  141. Application.Iteration = () => {
  142. Application.RequestStop ();
  143. };
  144. // NOTE: Run<T>, when called after Init has been called behaves differently than
  145. // when called if Init has not been called.
  146. Toplevel topLevel = null;
  147. Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
  148. RunState runstate = null;
  149. EventHandler<RunStateEventArgs> NewRunStateFn = (s, e) => {
  150. Assert.NotNull (e.State);
  151. runstate = e.State;
  152. };
  153. Application.NotifyNewRunState += NewRunStateFn;
  154. var rs = Application.Begin (topLevel);
  155. Assert.NotNull (rs);
  156. Assert.NotNull (runstate);
  157. Assert.Equal (rs, runstate);
  158. Assert.Equal (topLevel, Application.Top);
  159. Assert.Equal (topLevel, Application.Current);
  160. Application.NotifyNewRunState -= NewRunStateFn;
  161. Application.End (runstate);
  162. Assert.Null (Application.Current);
  163. Assert.NotNull (Application.Top);
  164. Assert.NotNull (Application.MainLoop);
  165. Assert.NotNull (Application.Driver);
  166. Shutdown ();
  167. Assert.Null (Application.Top);
  168. Assert.Null (Application.MainLoop);
  169. Assert.Null (Application.Driver);
  170. }
  171. [Fact]
  172. public void Begin_Null_Toplevel_Throws ()
  173. {
  174. // Setup Mock driver
  175. Init ();
  176. // Test null Toplevel
  177. Assert.Throws<ArgumentNullException> (() => Application.Begin (null));
  178. Shutdown ();
  179. Assert.Null (Application.Top);
  180. Assert.Null (Application.MainLoop);
  181. Assert.Null (Application.Driver);
  182. }
  183. #region RunTests
  184. [Fact]
  185. public void Run_T_After_InitWithDriver_with_TopLevel_Throws ()
  186. {
  187. // Setup Mock driver
  188. Init ();
  189. // Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
  190. Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (errorHandler: null));
  191. Shutdown ();
  192. Assert.Null (Application.Top);
  193. Assert.Null (Application.MainLoop);
  194. Assert.Null (Application.Driver);
  195. }
  196. [Fact]
  197. public void Run_T_After_InitWithDriver_with_TopLevel_and_Driver_Throws ()
  198. {
  199. // Setup Mock driver
  200. Init ();
  201. // Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
  202. Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (errorHandler: null, new FakeDriver ()));
  203. Shutdown ();
  204. Assert.Null (Application.Top);
  205. Assert.Null (Application.MainLoop);
  206. Assert.Null (Application.Driver);
  207. }
  208. [Fact]
  209. public void Run_T_After_InitWithDriver_with_TestTopLevel_DoesNotThrow ()
  210. {
  211. // Setup Mock driver
  212. Init ();
  213. Application.Iteration = () => {
  214. Application.RequestStop ();
  215. };
  216. // Init has been called and we're passing no driver to Run<TestTopLevel>. This is ok.
  217. Application.Run<TestToplevel> ();
  218. Shutdown ();
  219. Assert.Null (Application.Top);
  220. Assert.Null (Application.MainLoop);
  221. Assert.Null (Application.Driver);
  222. }
  223. [Fact]
  224. public void Run_T_After_InitNullDriver_with_TestTopLevel_Throws ()
  225. {
  226. Application._forceFakeConsole = true;
  227. Application.Init (null, null);
  228. Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ());
  229. Application.Iteration = () => {
  230. Application.RequestStop ();
  231. };
  232. // Init has been called without selecting a driver and we're passing no driver to Run<TestTopLevel>. Bad
  233. Application.Run<TestToplevel> ();
  234. Shutdown ();
  235. Assert.Null (Application.Top);
  236. Assert.Null (Application.MainLoop);
  237. Assert.Null (Application.Driver);
  238. }
  239. [Fact]
  240. public void Run_T_Init_Driver_Cleared_with_TestTopLevel_Throws ()
  241. {
  242. Init ();
  243. Application.Driver = null;
  244. Application.Iteration = () => {
  245. Application.RequestStop ();
  246. };
  247. // Init has been called, but Driver has been set to null. Bad.
  248. Assert.Throws<InvalidOperationException> (() => Application.Run<TestToplevel> ());
  249. Shutdown ();
  250. Assert.Null (Application.Top);
  251. Assert.Null (Application.MainLoop);
  252. Assert.Null (Application.Driver);
  253. }
  254. [Fact]
  255. public void Run_T_NoInit_DoesNotThrow ()
  256. {
  257. Application._forceFakeConsole = true;
  258. Application.Iteration = () => {
  259. Application.RequestStop ();
  260. };
  261. Application.Run<TestToplevel> ();
  262. Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ());
  263. Shutdown ();
  264. Assert.Null (Application.Top);
  265. Assert.Null (Application.MainLoop);
  266. Assert.Null (Application.Driver);
  267. }
  268. [Fact]
  269. public void Run_T_NoInit_WithDriver_DoesNotThrow ()
  270. {
  271. Application.Iteration = () => {
  272. Application.RequestStop ();
  273. };
  274. // Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
  275. Application.Run<TestToplevel> (errorHandler: null, new FakeDriver ());
  276. Shutdown ();
  277. Assert.Null (Application.Top);
  278. Assert.Null (Application.MainLoop);
  279. Assert.Null (Application.Driver);
  280. }
  281. [Fact]
  282. public void Run_RequestStop_Stops ()
  283. {
  284. // Setup Mock driver
  285. Init ();
  286. var top = new Toplevel ();
  287. var rs = Application.Begin (top);
  288. Assert.NotNull (rs);
  289. Assert.Equal (top, Application.Current);
  290. Application.Iteration = () => {
  291. Application.RequestStop ();
  292. };
  293. Application.Run (top);
  294. Application.Shutdown ();
  295. Assert.Null (Application.Current);
  296. Assert.Null (Application.Top);
  297. Assert.Null (Application.MainLoop);
  298. Assert.Null (Application.Driver);
  299. }
  300. [Fact]
  301. public void Run_RunningFalse_Stops ()
  302. {
  303. // Setup Mock driver
  304. Init ();
  305. var top = new Toplevel ();
  306. var rs = Application.Begin (top);
  307. Assert.NotNull (rs);
  308. Assert.Equal (top, Application.Current);
  309. Application.Iteration = () => {
  310. top.Running = false;
  311. };
  312. Application.Run (top);
  313. Application.Shutdown ();
  314. Assert.Null (Application.Current);
  315. Assert.Null (Application.Top);
  316. Assert.Null (Application.MainLoop);
  317. Assert.Null (Application.Driver);
  318. }
  319. [Fact]
  320. public void Run_Loaded_Ready_Unlodaded_Events ()
  321. {
  322. Init ();
  323. var top = Application.Top;
  324. var count = 0;
  325. top.Loaded += (s, e) => count++;
  326. top.Ready += (s, e) => count++;
  327. top.Unloaded += (s, e) => count++;
  328. Application.Iteration = () => Application.RequestStop ();
  329. Application.Run ();
  330. Application.Shutdown ();
  331. Assert.Equal (3, count);
  332. }
  333. // TODO: Add tests for Run that test errorHandler
  334. #endregion
  335. #region ShutdownTests
  336. [Fact]
  337. public void Shutdown_Allows_Async ()
  338. {
  339. static async Task TaskWithAsyncContinuation ()
  340. {
  341. await Task.Yield ();
  342. await Task.Yield ();
  343. }
  344. Init ();
  345. Application.Shutdown ();
  346. var task = TaskWithAsyncContinuation ();
  347. Thread.Sleep (20);
  348. Assert.True (task.IsCompletedSuccessfully);
  349. }
  350. [Fact]
  351. public void Shutdown_Resets_SyncContext ()
  352. {
  353. Init ();
  354. Application.Shutdown ();
  355. Assert.Null (SynchronizationContext.Current);
  356. }
  357. #endregion
  358. [Fact, AutoInitShutdown]
  359. public void Begin_Sets_Application_Top_To_Console_Size ()
  360. {
  361. Assert.Equal (new Rect (0, 0, 80, 25), Application.Top.Frame);
  362. ((FakeDriver)Application.Driver).SetBufferSize (5, 5);
  363. Application.Begin (Application.Top);
  364. Assert.Equal (new Rect (0, 0, 80, 25), Application.Top.Frame);
  365. ((FakeDriver)Application.Driver).SetBufferSize (5, 5);
  366. Assert.Equal (new Rect (0, 0, 5, 5), Application.Top.Frame);
  367. }
  368. [Fact]
  369. [AutoInitShutdown]
  370. public void SetCurrentAsTop_Run_A_Not_Modal_Toplevel_Make_It_The_Current_Application_Top ()
  371. {
  372. var t1 = new Toplevel ();
  373. var t2 = new Toplevel ();
  374. var t3 = new Toplevel ();
  375. var d = new Dialog ();
  376. var t4 = new Toplevel ();
  377. // t1, t2, t3, d, t4
  378. var iterations = 5;
  379. t1.Ready += (s, e) => {
  380. Assert.Equal (t1, Application.Top);
  381. Application.Run (t2);
  382. };
  383. t2.Ready += (s, e) => {
  384. Assert.Equal (t2, Application.Top);
  385. Application.Run (t3);
  386. };
  387. t3.Ready += (s, e) => {
  388. Assert.Equal (t3, Application.Top);
  389. Application.Run (d);
  390. };
  391. d.Ready += (s, e) => {
  392. Assert.Equal (t3, Application.Top);
  393. Application.Run (t4);
  394. };
  395. t4.Ready += (s, e) => {
  396. Assert.Equal (t4, Application.Top);
  397. t4.RequestStop ();
  398. d.RequestStop ();
  399. t3.RequestStop ();
  400. t2.RequestStop ();
  401. };
  402. // Now this will close the OverlappedContainer when all OverlappedChildren was closed
  403. t2.Closed += (s, _) => {
  404. t1.RequestStop ();
  405. };
  406. Application.Iteration += () => {
  407. if (iterations == 5) {
  408. // The Current still is t4 because Current.Running is false.
  409. Assert.Equal (t4, Application.Current);
  410. Assert.False (Application.Current.Running);
  411. Assert.Equal (t4, Application.Top);
  412. } else if (iterations == 4) {
  413. // The Current is d and Current.Running is false.
  414. Assert.Equal (d, Application.Current);
  415. Assert.False (Application.Current.Running);
  416. Assert.Equal (t4, Application.Top);
  417. } else if (iterations == 3) {
  418. // The Current is t3 and Current.Running is false.
  419. Assert.Equal (t3, Application.Current);
  420. Assert.False (Application.Current.Running);
  421. Assert.Equal (t3, Application.Top);
  422. } else if (iterations == 2) {
  423. // The Current is t2 and Current.Running is false.
  424. Assert.Equal (t2, Application.Current);
  425. Assert.False (Application.Current.Running);
  426. Assert.Equal (t2, Application.Top);
  427. } else {
  428. // The Current is t1.
  429. Assert.Equal (t1, Application.Current);
  430. Assert.False (Application.Current.Running);
  431. Assert.Equal (t1, Application.Top);
  432. }
  433. iterations--;
  434. };
  435. Application.Run (t1);
  436. Assert.Equal (t1, Application.Top);
  437. }
  438. [Fact]
  439. [AutoInitShutdown]
  440. public void Internal_Properties_Correct ()
  441. {
  442. Assert.True (Application._initialized);
  443. Assert.NotNull (Application.Top);
  444. var rs = Application.Begin (Application.Top);
  445. Assert.Equal (Application.Top, rs.Toplevel);
  446. Assert.Null (Application.MouseGrabView); // public
  447. Assert.Null (Application.WantContinuousButtonPressedView); // public
  448. Assert.False (Application.MoveToOverlappedChild (Application.Top));
  449. }
  450. #region KeyboardTests
  451. [Fact]
  452. public void KeyUp_Event ()
  453. {
  454. // Setup Mock driver
  455. Init ();
  456. // Setup some fake keypresses (This)
  457. var input = "Tests";
  458. // Put a control-q in at the end
  459. FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true));
  460. foreach (var c in input.Reverse ()) {
  461. if (char.IsLetter (c)) {
  462. FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false));
  463. } else {
  464. FakeConsole.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false));
  465. }
  466. }
  467. int stackSize = FakeConsole.MockKeyPresses.Count;
  468. int iterations = 0;
  469. Application.Iteration = () => {
  470. iterations++;
  471. // Stop if we run out of control...
  472. if (iterations > 10) {
  473. Application.RequestStop ();
  474. }
  475. };
  476. int keyUps = 0;
  477. var output = string.Empty;
  478. Application.Top.KeyUp += (object sender, KeyEventEventArgs args) => {
  479. if (args.KeyEvent.Key != (Key.CtrlMask | Key.Q)) {
  480. output += (char)args.KeyEvent.KeyValue;
  481. }
  482. keyUps++;
  483. };
  484. Application.Run (Application.Top);
  485. // Input string should match output
  486. Assert.Equal (input, output);
  487. // # of key up events should match stack size
  488. //Assert.Equal (stackSize, keyUps);
  489. // We can't use numbers variables on the left side of an Assert.Equal/NotEqual,
  490. // it must be literal (Linux only).
  491. Assert.Equal (6, keyUps);
  492. // # of key up events should match # of iterations
  493. Assert.Equal (stackSize, iterations);
  494. Application.Shutdown ();
  495. Assert.Null (Application.Current);
  496. Assert.Null (Application.Top);
  497. Assert.Null (Application.MainLoop);
  498. Assert.Null (Application.Driver);
  499. }
  500. [Fact]
  501. public void AlternateForwardKey_AlternateBackwardKey_Tests ()
  502. {
  503. Init ();
  504. var top = Application.Top;
  505. var w1 = new Window ();
  506. var v1 = new TextField ();
  507. var v2 = new TextView ();
  508. w1.Add (v1, v2);
  509. var w2 = new Window ();
  510. var v3 = new CheckBox ();
  511. var v4 = new Button ();
  512. w2.Add (v3, v4);
  513. top.Add (w1, w2);
  514. Application.Iteration += () => {
  515. Assert.True (v1.HasFocus);
  516. // Using default keys.
  517. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  518. new KeyModifiers () { Ctrl = true }));
  519. Assert.True (v2.HasFocus);
  520. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  521. new KeyModifiers () { Ctrl = true }));
  522. Assert.True (v3.HasFocus);
  523. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  524. new KeyModifiers () { Ctrl = true }));
  525. Assert.True (v4.HasFocus);
  526. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  527. new KeyModifiers () { Ctrl = true }));
  528. Assert.True (v1.HasFocus);
  529. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  530. new KeyModifiers () { Shift = true, Ctrl = true }));
  531. Assert.True (v4.HasFocus);
  532. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  533. new KeyModifiers () { Shift = true, Ctrl = true }));
  534. Assert.True (v3.HasFocus);
  535. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  536. new KeyModifiers () { Shift = true, Ctrl = true }));
  537. Assert.True (v2.HasFocus);
  538. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  539. new KeyModifiers () { Shift = true, Ctrl = true }));
  540. Assert.True (v1.HasFocus);
  541. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  542. new KeyModifiers () { Ctrl = true }));
  543. Assert.True (v2.HasFocus);
  544. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  545. new KeyModifiers () { Ctrl = true }));
  546. Assert.True (v3.HasFocus);
  547. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  548. new KeyModifiers () { Ctrl = true }));
  549. Assert.True (v4.HasFocus);
  550. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  551. new KeyModifiers () { Ctrl = true }));
  552. Assert.True (v1.HasFocus);
  553. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  554. new KeyModifiers () { Ctrl = true }));
  555. Assert.True (v4.HasFocus);
  556. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  557. new KeyModifiers () { Ctrl = true }));
  558. Assert.True (v3.HasFocus);
  559. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  560. new KeyModifiers () { Ctrl = true }));
  561. Assert.True (v2.HasFocus);
  562. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  563. new KeyModifiers () { Ctrl = true }));
  564. Assert.True (v1.HasFocus);
  565. // Using another's alternate keys.
  566. Application.AlternateForwardKey = Key.F7;
  567. Application.AlternateBackwardKey = Key.F6;
  568. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  569. Assert.True (v2.HasFocus);
  570. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  571. Assert.True (v3.HasFocus);
  572. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  573. Assert.True (v4.HasFocus);
  574. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  575. Assert.True (v1.HasFocus);
  576. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  577. Assert.True (v4.HasFocus);
  578. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  579. Assert.True (v3.HasFocus);
  580. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  581. Assert.True (v2.HasFocus);
  582. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  583. Assert.True (v1.HasFocus);
  584. Application.RequestStop ();
  585. };
  586. Application.Run (top);
  587. // Replacing the defaults keys to avoid errors on others unit tests that are using it.
  588. Application.AlternateForwardKey = Key.PageDown | Key.CtrlMask;
  589. Application.AlternateBackwardKey = Key.PageUp | Key.CtrlMask;
  590. Application.QuitKey = Key.Q | Key.CtrlMask;
  591. Assert.Equal (Key.PageDown | Key.CtrlMask, Application.AlternateForwardKey);
  592. Assert.Equal (Key.PageUp | Key.CtrlMask, Application.AlternateBackwardKey);
  593. Assert.Equal (Key.Q | Key.CtrlMask, Application.QuitKey);
  594. // Shutdown must be called to safely clean up Application if Init has been called
  595. Application.Shutdown ();
  596. }
  597. [Fact]
  598. [AutoInitShutdown]
  599. public void QuitKey_Getter_Setter ()
  600. {
  601. var top = Application.Top;
  602. var isQuiting = false;
  603. top.Closing += (s, e) => {
  604. isQuiting = true;
  605. e.Cancel = true;
  606. };
  607. Application.Begin (top);
  608. top.Running = true;
  609. Assert.Equal (Key.Q | Key.CtrlMask, Application.QuitKey);
  610. Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true);
  611. Assert.True (isQuiting);
  612. isQuiting = false;
  613. Application.QuitKey = Key.C | Key.CtrlMask;
  614. Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true);
  615. Assert.False (isQuiting);
  616. Application.Driver.SendKeys ('c', ConsoleKey.C, false, false, true);
  617. Assert.True (isQuiting);
  618. // Reset the QuitKey to avoid throws errors on another tests
  619. Application.QuitKey = Key.Q | Key.CtrlMask;
  620. }
  621. [Fact]
  622. [AutoInitShutdown]
  623. public void EnsuresTopOnFront_CanFocus_True_By_Keyboard_And_Mouse ()
  624. {
  625. var top = Application.Top;
  626. var win = new Window () { Title = "win", X = 0, Y = 0, Width = 20, Height = 10 };
  627. var tf = new TextField () { Width = 10 };
  628. win.Add (tf);
  629. var win2 = new Window () { Title = "win2", X = 22, Y = 0, Width = 20, Height = 10 };
  630. var tf2 = new TextField () { Width = 10 };
  631. win2.Add (tf2);
  632. top.Add (win, win2);
  633. Application.Begin (top);
  634. Assert.True (win.CanFocus);
  635. Assert.True (win.HasFocus);
  636. Assert.True (win2.CanFocus);
  637. Assert.False (win2.HasFocus);
  638. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  639. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  640. Assert.True (win.CanFocus);
  641. Assert.False (win.HasFocus);
  642. Assert.True (win2.CanFocus);
  643. Assert.True (win2.HasFocus);
  644. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  645. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  646. Assert.True (win.CanFocus);
  647. Assert.True (win.HasFocus);
  648. Assert.True (win2.CanFocus);
  649. Assert.False (win2.HasFocus);
  650. Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  651. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
  652. Assert.True (win.CanFocus);
  653. Assert.False (win.HasFocus);
  654. Assert.True (win2.CanFocus);
  655. Assert.True (win2.HasFocus);
  656. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  657. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
  658. Assert.Null (Toplevel._dragPosition);
  659. }
  660. [Fact]
  661. [AutoInitShutdown]
  662. public void EnsuresTopOnFront_CanFocus_False_By_Keyboard_And_Mouse ()
  663. {
  664. var top = Application.Top;
  665. var win = new Window () { Title = "win", X = 0, Y = 0, Width = 20, Height = 10 };
  666. var tf = new TextField () { Width = 10 };
  667. win.Add (tf);
  668. var win2 = new Window () { Title = "win2", X = 22, Y = 0, Width = 20, Height = 10 };
  669. var tf2 = new TextField () { Width = 10 };
  670. win2.Add (tf2);
  671. top.Add (win, win2);
  672. Application.Begin (top);
  673. Assert.True (win.CanFocus);
  674. Assert.True (win.HasFocus);
  675. Assert.True (win2.CanFocus);
  676. Assert.False (win2.HasFocus);
  677. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  678. win.CanFocus = false;
  679. Assert.False (win.CanFocus);
  680. Assert.False (win.HasFocus);
  681. Assert.True (win2.CanFocus);
  682. Assert.True (win2.HasFocus);
  683. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  684. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  685. Assert.True (win2.CanFocus);
  686. Assert.False (win.HasFocus);
  687. Assert.True (win2.CanFocus);
  688. Assert.True (win2.HasFocus);
  689. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  690. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  691. Assert.False (win.CanFocus);
  692. Assert.False (win.HasFocus);
  693. Assert.True (win2.CanFocus);
  694. Assert.True (win2.HasFocus);
  695. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  696. win.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
  697. Assert.False (win.CanFocus);
  698. Assert.False (win.HasFocus);
  699. Assert.True (win2.CanFocus);
  700. Assert.True (win2.HasFocus);
  701. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  702. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
  703. Assert.Null (Toplevel._dragPosition);
  704. }
  705. #endregion
  706. #region mousegrabtests
  707. [Fact, AutoInitShutdown]
  708. public void MouseGrabView_WithNullMouseEventView ()
  709. {
  710. var tf = new TextField () { Width = 10 };
  711. var sv = new ScrollView () {
  712. Width = Dim.Fill (),
  713. Height = Dim.Fill (),
  714. ContentSize = new Size (100, 100)
  715. };
  716. sv.Add (tf);
  717. Application.Top.Add (sv);
  718. var iterations = -1;
  719. Application.Iteration = () => {
  720. iterations++;
  721. if (iterations == 0) {
  722. Assert.True (tf.HasFocus);
  723. Assert.Null (Application.MouseGrabView);
  724. ReflectionTools.InvokePrivate (
  725. typeof (Application),
  726. "ProcessMouseEvent",
  727. new MouseEvent () {
  728. X = 5,
  729. Y = 5,
  730. Flags = MouseFlags.ReportMousePosition
  731. });
  732. Assert.Equal (sv, Application.MouseGrabView);
  733. MessageBox.Query ("Title", "Test", "Ok");
  734. Assert.Null (Application.MouseGrabView);
  735. } else if (iterations == 1) {
  736. // Application.MouseGrabView is null because
  737. // another toplevel (Dialog) was opened
  738. Assert.Null (Application.MouseGrabView);
  739. ReflectionTools.InvokePrivate (
  740. typeof (Application),
  741. "ProcessMouseEvent",
  742. new MouseEvent () {
  743. X = 5,
  744. Y = 5,
  745. Flags = MouseFlags.ReportMousePosition
  746. });
  747. Assert.Null (Application.MouseGrabView);
  748. ReflectionTools.InvokePrivate (
  749. typeof (Application),
  750. "ProcessMouseEvent",
  751. new MouseEvent () {
  752. X = 40,
  753. Y = 12,
  754. Flags = MouseFlags.ReportMousePosition
  755. });
  756. Assert.Null (Application.MouseGrabView);
  757. ReflectionTools.InvokePrivate (
  758. typeof (Application),
  759. "ProcessMouseEvent",
  760. new MouseEvent () {
  761. X = 0,
  762. Y = 0,
  763. Flags = MouseFlags.Button1Pressed
  764. });
  765. Assert.Null (Application.MouseGrabView);
  766. Application.RequestStop ();
  767. } else if (iterations == 2) {
  768. Assert.Null (Application.MouseGrabView);
  769. Application.RequestStop ();
  770. }
  771. };
  772. Application.Run ();
  773. }
  774. [Fact, AutoInitShutdown]
  775. public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
  776. {
  777. View grabView = null;
  778. var count = 0;
  779. var view1 = new View ();
  780. var view2 = new View ();
  781. Application.GrabbedMouse += Application_GrabbedMouse;
  782. Application.UnGrabbedMouse += Application_UnGrabbedMouse;
  783. Application.GrabMouse (view1);
  784. Assert.Equal (0, count);
  785. Assert.Equal (grabView, view1);
  786. Assert.Equal (view1, Application.MouseGrabView);
  787. Application.UngrabMouse ();
  788. Assert.Equal (1, count);
  789. Assert.Equal (grabView, view1);
  790. Assert.Null (Application.MouseGrabView);
  791. Application.GrabbedMouse += Application_GrabbedMouse;
  792. Application.UnGrabbedMouse += Application_UnGrabbedMouse;
  793. Application.GrabMouse (view2);
  794. Assert.Equal (1, count);
  795. Assert.Equal (grabView, view2);
  796. Assert.Equal (view2, Application.MouseGrabView);
  797. Application.UngrabMouse ();
  798. Assert.Equal (2, count);
  799. Assert.Equal (grabView, view2);
  800. Assert.Null (Application.MouseGrabView);
  801. void Application_GrabbedMouse (object sender, ViewEventArgs e)
  802. {
  803. if (count == 0) {
  804. Assert.Equal (view1, e.View);
  805. grabView = view1;
  806. } else {
  807. Assert.Equal (view2, e.View);
  808. grabView = view2;
  809. }
  810. Application.GrabbedMouse -= Application_GrabbedMouse;
  811. }
  812. void Application_UnGrabbedMouse (object sender, ViewEventArgs e)
  813. {
  814. if (count == 0) {
  815. Assert.Equal (view1, e.View);
  816. Assert.Equal (grabView, e.View);
  817. } else {
  818. Assert.Equal (view2, e.View);
  819. Assert.Equal (grabView, e.View);
  820. }
  821. count++;
  822. Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
  823. }
  824. }
  825. #endregion
  826. }
  827. }