ApplicationTests.cs 28 KB

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