ApplicationTests.cs 27 KB

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