ApplicationTests.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339
  1. using System;
  2. using System.Linq;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using Xunit;
  6. // Alias Console to MockConsole so we don't accidentally use Console
  7. using Console = Terminal.Gui.FakeConsole;
  8. namespace Terminal.Gui.Core {
  9. public class ApplicationTests {
  10. public ApplicationTests ()
  11. {
  12. #if DEBUG_IDISPOSABLE
  13. Responder.Instances.Clear ();
  14. #endif
  15. }
  16. [Fact]
  17. public void Init_Shutdown_Cleans_Up ()
  18. {
  19. // Verify initial state is per spec
  20. Pre_Init_State ();
  21. Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
  22. // Verify post-Init state is correct
  23. Post_Init_State ();
  24. // MockDriver is always 80x25
  25. Assert.Equal (80, Application.Driver.Cols);
  26. Assert.Equal (25, Application.Driver.Rows);
  27. Application.Shutdown ();
  28. // Verify state is back to initial
  29. Pre_Init_State ();
  30. }
  31. void Pre_Init_State ()
  32. {
  33. Assert.Null (Application.Driver);
  34. Assert.Null (Application.Top);
  35. Assert.Null (Application.Current);
  36. Assert.Throws<ArgumentNullException> (() => Application.HeightAsBuffer == true);
  37. Assert.False (Application.AlwaysSetPosition);
  38. Assert.Null (Application.MainLoop);
  39. Assert.Null (Application.Iteration);
  40. Assert.Null (Application.RootMouseEvent);
  41. Assert.Null (Application.Resized);
  42. }
  43. void Post_Init_State ()
  44. {
  45. Assert.NotNull (Application.Driver);
  46. Assert.NotNull (Application.Top);
  47. Assert.NotNull (Application.Current);
  48. Assert.False (Application.HeightAsBuffer);
  49. Assert.False (Application.AlwaysSetPosition);
  50. Assert.NotNull (Application.MainLoop);
  51. Assert.Null (Application.Iteration);
  52. Assert.Null (Application.RootMouseEvent);
  53. Assert.Null (Application.Resized);
  54. }
  55. [Fact]
  56. public void RunState_Dispose_Cleans_Up ()
  57. {
  58. var rs = new Application.RunState (null);
  59. Assert.NotNull (rs);
  60. // Should not throw because Toplevel was null
  61. rs.Dispose ();
  62. var top = new Toplevel ();
  63. rs = new Application.RunState (top);
  64. Assert.NotNull (rs);
  65. // Should throw because there's no stack
  66. Assert.Throws<InvalidOperationException> (() => rs.Dispose ());
  67. }
  68. void Init ()
  69. {
  70. Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
  71. Assert.NotNull (Application.Driver);
  72. Assert.NotNull (Application.MainLoop);
  73. }
  74. void Shutdown ()
  75. {
  76. Application.Shutdown ();
  77. }
  78. [Fact]
  79. public void Begin_End_Cleana_Up ()
  80. {
  81. // Setup Mock driver
  82. Init ();
  83. // Test null Toplevel
  84. Assert.Throws<ArgumentNullException> (() => Application.Begin (null));
  85. var top = new Toplevel ();
  86. var rs = Application.Begin (top);
  87. Assert.NotNull (rs);
  88. Assert.Equal (top, Application.Current);
  89. Application.End (rs);
  90. Assert.Null (Application.Current);
  91. Assert.NotNull (Application.Top);
  92. Assert.NotNull (Application.MainLoop);
  93. Assert.NotNull (Application.Driver);
  94. Shutdown ();
  95. Assert.Null (Application.Top);
  96. Assert.Null (Application.MainLoop);
  97. Assert.Null (Application.Driver);
  98. }
  99. [Fact]
  100. public void RequestStop_Stops ()
  101. {
  102. // Setup Mock driver
  103. Init ();
  104. var top = new Toplevel ();
  105. var rs = Application.Begin (top);
  106. Assert.NotNull (rs);
  107. Assert.Equal (top, Application.Current);
  108. Application.Iteration = () => {
  109. Application.RequestStop ();
  110. };
  111. Application.Run (top);
  112. Application.Shutdown ();
  113. Assert.Null (Application.Current);
  114. Assert.Null (Application.Top);
  115. Assert.Null (Application.MainLoop);
  116. Assert.Null (Application.Driver);
  117. }
  118. [Fact]
  119. public void RunningFalse_Stops ()
  120. {
  121. // Setup Mock driver
  122. Init ();
  123. var top = new Toplevel ();
  124. var rs = Application.Begin (top);
  125. Assert.NotNull (rs);
  126. Assert.Equal (top, Application.Current);
  127. Application.Iteration = () => {
  128. top.Running = false;
  129. };
  130. Application.Run (top);
  131. Application.Shutdown ();
  132. Assert.Null (Application.Current);
  133. Assert.Null (Application.Top);
  134. Assert.Null (Application.MainLoop);
  135. Assert.Null (Application.Driver);
  136. }
  137. [Fact]
  138. public void KeyUp_Event ()
  139. {
  140. // Setup Mock driver
  141. Init ();
  142. // Setup some fake keypresses (This)
  143. var input = "Tests";
  144. // Put a control-q in at the end
  145. Console.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true));
  146. foreach (var c in input.Reverse ()) {
  147. if (char.IsLetter (c)) {
  148. Console.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false));
  149. } else {
  150. Console.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false));
  151. }
  152. }
  153. int stackSize = Console.MockKeyPresses.Count;
  154. int iterations = 0;
  155. Application.Iteration = () => {
  156. iterations++;
  157. // Stop if we run out of control...
  158. if (iterations > 10) {
  159. Application.RequestStop ();
  160. }
  161. };
  162. int keyUps = 0;
  163. var output = string.Empty;
  164. Application.Top.KeyUp += (View.KeyEventEventArgs args) => {
  165. if (args.KeyEvent.Key != (Key.CtrlMask | Key.Q)) {
  166. output += (char)args.KeyEvent.KeyValue;
  167. }
  168. keyUps++;
  169. };
  170. Application.Run (Application.Top);
  171. // Input string should match output
  172. Assert.Equal (input, output);
  173. // # of key up events should match stack size
  174. //Assert.Equal (stackSize, keyUps);
  175. // We can't use numbers variables on the left side of an Assert.Equal/NotEqual,
  176. // it must be literal (Linux only).
  177. Assert.Equal (6, keyUps);
  178. // # of key up events should match # of iterations
  179. Assert.Equal (stackSize, iterations);
  180. Application.Shutdown ();
  181. Assert.Null (Application.Current);
  182. Assert.Null (Application.Top);
  183. Assert.Null (Application.MainLoop);
  184. Assert.Null (Application.Driver);
  185. }
  186. [Fact]
  187. public void Loaded_Ready_Unlodaded_Events ()
  188. {
  189. Init ();
  190. var top = Application.Top;
  191. var count = 0;
  192. top.Loaded += () => count++;
  193. top.Ready += () => count++;
  194. top.Unloaded += () => count++;
  195. Application.Iteration = () => Application.RequestStop ();
  196. Application.Run ();
  197. Application.Shutdown ();
  198. Assert.Equal (3, count);
  199. }
  200. [Fact]
  201. public void Shutdown_Allows_Async ()
  202. {
  203. static async Task TaskWithAsyncContinuation ()
  204. {
  205. await Task.Yield ();
  206. await Task.Yield ();
  207. }
  208. Init ();
  209. Application.Shutdown ();
  210. var task = TaskWithAsyncContinuation ();
  211. Thread.Sleep (20);
  212. Assert.True (task.IsCompletedSuccessfully);
  213. }
  214. [Fact]
  215. public void Shutdown_Resets_SyncContext ()
  216. {
  217. Init ();
  218. Application.Shutdown ();
  219. Assert.Null (SynchronizationContext.Current);
  220. }
  221. [Fact]
  222. public void AlternateForwardKey_AlternateBackwardKey_Tests ()
  223. {
  224. Init ();
  225. var top = Application.Top;
  226. var w1 = new Window ();
  227. var v1 = new TextField ();
  228. var v2 = new TextView ();
  229. w1.Add (v1, v2);
  230. var w2 = new Window ();
  231. var v3 = new CheckBox ();
  232. var v4 = new Button ();
  233. w2.Add (v3, v4);
  234. top.Add (w1, w2);
  235. Application.Iteration += () => {
  236. Assert.True (v1.HasFocus);
  237. // Using default keys.
  238. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  239. new KeyModifiers () { Ctrl = true }));
  240. Assert.True (v2.HasFocus);
  241. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  242. new KeyModifiers () { Ctrl = true }));
  243. Assert.True (v3.HasFocus);
  244. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  245. new KeyModifiers () { Ctrl = true }));
  246. Assert.True (v4.HasFocus);
  247. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab,
  248. new KeyModifiers () { Ctrl = true }));
  249. Assert.True (v1.HasFocus);
  250. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  251. new KeyModifiers () { Shift = true, Ctrl = true }));
  252. Assert.True (v4.HasFocus);
  253. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  254. new KeyModifiers () { Shift = true, Ctrl = true }));
  255. Assert.True (v3.HasFocus);
  256. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  257. new KeyModifiers () { Shift = true, Ctrl = true }));
  258. Assert.True (v2.HasFocus);
  259. top.ProcessKey (new KeyEvent (Key.ShiftMask | Key.CtrlMask | Key.Tab,
  260. new KeyModifiers () { Shift = true, Ctrl = true }));
  261. Assert.True (v1.HasFocus);
  262. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  263. new KeyModifiers () { Ctrl = true }));
  264. Assert.True (v2.HasFocus);
  265. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  266. new KeyModifiers () { Ctrl = true }));
  267. Assert.True (v3.HasFocus);
  268. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  269. new KeyModifiers () { Ctrl = true }));
  270. Assert.True (v4.HasFocus);
  271. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageDown,
  272. new KeyModifiers () { Ctrl = true }));
  273. Assert.True (v1.HasFocus);
  274. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  275. new KeyModifiers () { Ctrl = true }));
  276. Assert.True (v4.HasFocus);
  277. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  278. new KeyModifiers () { Ctrl = true }));
  279. Assert.True (v3.HasFocus);
  280. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  281. new KeyModifiers () { Ctrl = true }));
  282. Assert.True (v2.HasFocus);
  283. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.PageUp,
  284. new KeyModifiers () { Ctrl = true }));
  285. Assert.True (v1.HasFocus);
  286. // Using another's alternate keys.
  287. Application.AlternateForwardKey = Key.F7;
  288. Application.AlternateBackwardKey = Key.F6;
  289. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  290. Assert.True (v2.HasFocus);
  291. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  292. Assert.True (v3.HasFocus);
  293. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  294. Assert.True (v4.HasFocus);
  295. top.ProcessKey (new KeyEvent (Key.F7, new KeyModifiers ()));
  296. Assert.True (v1.HasFocus);
  297. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  298. Assert.True (v4.HasFocus);
  299. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  300. Assert.True (v3.HasFocus);
  301. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  302. Assert.True (v2.HasFocus);
  303. top.ProcessKey (new KeyEvent (Key.F6, new KeyModifiers ()));
  304. Assert.True (v1.HasFocus);
  305. Application.RequestStop ();
  306. };
  307. Application.Run (top);
  308. // Replacing the defaults keys to avoid errors on others unit tests that are using it.
  309. Application.AlternateForwardKey = Key.PageDown | Key.CtrlMask;
  310. Application.AlternateBackwardKey = Key.PageUp | Key.CtrlMask;
  311. Application.QuitKey = Key.Q | Key.CtrlMask;
  312. Assert.Equal (Key.PageDown | Key.CtrlMask, Application.AlternateForwardKey);
  313. Assert.Equal (Key.PageUp | Key.CtrlMask, Application.AlternateBackwardKey);
  314. Assert.Equal (Key.Q | Key.CtrlMask, Application.QuitKey);
  315. // Shutdown must be called to safely clean up Application if Init has been called
  316. Application.Shutdown ();
  317. }
  318. [Fact]
  319. public void Application_RequestStop_With_Params_On_A_Not_MdiContainer_Always_Use_The_Application_Current ()
  320. {
  321. Init ();
  322. var top1 = new Toplevel ();
  323. var top2 = new Toplevel ();
  324. var top3 = new Window ();
  325. var top4 = new Window ();
  326. var d = new Dialog ();
  327. // top1, top2, top3, d1 = 4
  328. var iterations = 4;
  329. top1.Ready += () => {
  330. Assert.Null (Application.MdiChildes);
  331. Application.Run (top2);
  332. };
  333. top2.Ready += () => {
  334. Assert.Null (Application.MdiChildes);
  335. Application.Run (top3);
  336. };
  337. top3.Ready += () => {
  338. Assert.Null (Application.MdiChildes);
  339. Application.Run (top4);
  340. };
  341. top4.Ready += () => {
  342. Assert.Null (Application.MdiChildes);
  343. Application.Run (d);
  344. };
  345. d.Ready += () => {
  346. Assert.Null (Application.MdiChildes);
  347. // This will close the d because on a not MdiContainer the Application.Current it always used.
  348. Application.RequestStop (top1);
  349. Assert.True (Application.Current == d);
  350. };
  351. d.Closed += (e) => Application.RequestStop (top1);
  352. Application.Iteration += () => {
  353. Assert.Null (Application.MdiChildes);
  354. if (iterations == 4) {
  355. Assert.True (Application.Current == d);
  356. } else if (iterations == 3) {
  357. Assert.True (Application.Current == top4);
  358. } else if (iterations == 2) {
  359. Assert.True (Application.Current == top3);
  360. } else if (iterations == 1) {
  361. Assert.True (Application.Current == top2);
  362. } else {
  363. Assert.True (Application.Current == top1);
  364. }
  365. Application.RequestStop (top1);
  366. iterations--;
  367. };
  368. Application.Run (top1);
  369. Assert.Null (Application.MdiChildes);
  370. Application.Shutdown ();
  371. }
  372. class Mdi : Toplevel {
  373. public Mdi ()
  374. {
  375. IsMdiContainer = true;
  376. }
  377. }
  378. [Fact]
  379. public void MdiContainer_With_Toplevel_RequestStop_Balanced ()
  380. {
  381. Init ();
  382. var mdi = new Mdi ();
  383. var c1 = new Toplevel ();
  384. var c2 = new Window ();
  385. var c3 = new Window ();
  386. var d = new Dialog ();
  387. // MdiChild = c1, c2, c3
  388. // d1 = 1
  389. var iterations = 4;
  390. mdi.Ready += () => {
  391. Assert.Empty (Application.MdiChildes);
  392. Application.Run (c1);
  393. };
  394. c1.Ready += () => {
  395. Assert.Single (Application.MdiChildes);
  396. Application.Run (c2);
  397. };
  398. c2.Ready += () => {
  399. Assert.Equal (2, Application.MdiChildes.Count);
  400. Application.Run (c3);
  401. };
  402. c3.Ready += () => {
  403. Assert.Equal (3, Application.MdiChildes.Count);
  404. Application.Run (d);
  405. };
  406. // More easy because the Mdi Container handles all at once
  407. d.Ready += () => {
  408. Assert.Equal (3, Application.MdiChildes.Count);
  409. // This will not close the MdiContainer because d is a modal toplevel and will be closed.
  410. mdi.RequestStop ();
  411. };
  412. // Now this will close the MdiContainer propagating through the MdiChildes.
  413. d.Closed += (e) => {
  414. mdi.RequestStop ();
  415. };
  416. Application.Iteration += () => {
  417. if (iterations == 4) {
  418. // The Dialog was not closed before and will be closed now.
  419. Assert.True (Application.Current == d);
  420. Assert.False (d.Running);
  421. } else {
  422. Assert.Equal (iterations, Application.MdiChildes.Count);
  423. for (int i = 0; i < iterations; i++) {
  424. Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  425. }
  426. }
  427. iterations--;
  428. };
  429. Application.Run (mdi);
  430. Assert.Empty (Application.MdiChildes);
  431. Application.Shutdown ();
  432. }
  433. [Fact]
  434. public void MdiContainer_With_Application_RequestStop_MdiTop_With_Params ()
  435. {
  436. Init ();
  437. var mdi = new Mdi ();
  438. var c1 = new Toplevel ();
  439. var c2 = new Window ();
  440. var c3 = new Window ();
  441. var d = new Dialog ();
  442. // MdiChild = c1, c2, c3
  443. // d1 = 1
  444. var iterations = 4;
  445. mdi.Ready += () => {
  446. Assert.Empty (Application.MdiChildes);
  447. Application.Run (c1);
  448. };
  449. c1.Ready += () => {
  450. Assert.Single (Application.MdiChildes);
  451. Application.Run (c2);
  452. };
  453. c2.Ready += () => {
  454. Assert.Equal (2, Application.MdiChildes.Count);
  455. Application.Run (c3);
  456. };
  457. c3.Ready += () => {
  458. Assert.Equal (3, Application.MdiChildes.Count);
  459. Application.Run (d);
  460. };
  461. // Also easy because the Mdi Container handles all at once
  462. d.Ready += () => {
  463. Assert.Equal (3, Application.MdiChildes.Count);
  464. // This will not close the MdiContainer because d is a modal toplevel
  465. Application.RequestStop (mdi);
  466. };
  467. // Now this will close the MdiContainer propagating through the MdiChildes.
  468. d.Closed += (e) => Application.RequestStop (mdi);
  469. Application.Iteration += () => {
  470. if (iterations == 4) {
  471. // The Dialog was not closed before and will be closed now.
  472. Assert.True (Application.Current == d);
  473. Assert.False (d.Running);
  474. } else {
  475. Assert.Equal (iterations, Application.MdiChildes.Count);
  476. for (int i = 0; i < iterations; i++) {
  477. Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  478. }
  479. }
  480. iterations--;
  481. };
  482. Application.Run (mdi);
  483. Assert.Empty (Application.MdiChildes);
  484. Application.Shutdown ();
  485. }
  486. [Fact]
  487. public void MdiContainer_With_Application_RequestStop_MdiTop_Without_Params ()
  488. {
  489. Init ();
  490. var mdi = new Mdi ();
  491. var c1 = new Toplevel ();
  492. var c2 = new Window ();
  493. var c3 = new Window ();
  494. var d = new Dialog ();
  495. // MdiChild = c1, c2, c3 = 3
  496. // d1 = 1
  497. var iterations = 4;
  498. mdi.Ready += () => {
  499. Assert.Empty (Application.MdiChildes);
  500. Application.Run (c1);
  501. };
  502. c1.Ready += () => {
  503. Assert.Single (Application.MdiChildes);
  504. Application.Run (c2);
  505. };
  506. c2.Ready += () => {
  507. Assert.Equal (2, Application.MdiChildes.Count);
  508. Application.Run (c3);
  509. };
  510. c3.Ready += () => {
  511. Assert.Equal (3, Application.MdiChildes.Count);
  512. Application.Run (d);
  513. };
  514. //More harder because it's sequential.
  515. d.Ready += () => {
  516. Assert.Equal (3, Application.MdiChildes.Count);
  517. // Close the Dialog
  518. Application.RequestStop ();
  519. };
  520. // Now this will close the MdiContainer propagating through the MdiChildes.
  521. d.Closed += (e) => Application.RequestStop (mdi);
  522. Application.Iteration += () => {
  523. if (iterations == 4) {
  524. // The Dialog still is the current top and we can't request stop to MdiContainer
  525. // because we are not using parameter calls.
  526. Assert.True (Application.Current == d);
  527. Assert.False (d.Running);
  528. } else {
  529. Assert.Equal (iterations, Application.MdiChildes.Count);
  530. for (int i = 0; i < iterations; i++) {
  531. Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  532. }
  533. }
  534. iterations--;
  535. };
  536. Application.Run (mdi);
  537. Assert.Empty (Application.MdiChildes);
  538. Application.Shutdown ();
  539. }
  540. [Fact]
  541. public void IsMdiChild_Testing ()
  542. {
  543. Init ();
  544. var mdi = new Mdi ();
  545. var c1 = new Toplevel ();
  546. var c2 = new Window ();
  547. var c3 = new Window ();
  548. var d = new Dialog ();
  549. Application.Iteration += () => {
  550. Assert.False (mdi.IsMdiChild);
  551. Assert.True (c1.IsMdiChild);
  552. Assert.True (c2.IsMdiChild);
  553. Assert.True (c3.IsMdiChild);
  554. Assert.False (d.IsMdiChild);
  555. mdi.RequestStop ();
  556. };
  557. Application.Run (mdi);
  558. Application.Shutdown ();
  559. }
  560. [Fact]
  561. public void Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  562. {
  563. Init ();
  564. var mdi = new Mdi ();
  565. var c1 = new Toplevel ();
  566. var c2 = new Window ();
  567. var c3 = new Window ();
  568. var d1 = new Dialog ();
  569. var d2 = new Dialog ();
  570. // MdiChild = c1, c2, c3 = 3
  571. // d1, d2 = 2
  572. var iterations = 5;
  573. mdi.Ready += () => {
  574. Assert.Empty (Application.MdiChildes);
  575. Application.Run (c1);
  576. };
  577. c1.Ready += () => {
  578. Assert.Single (Application.MdiChildes);
  579. Application.Run (c2);
  580. };
  581. c2.Ready += () => {
  582. Assert.Equal (2, Application.MdiChildes.Count);
  583. Application.Run (c3);
  584. };
  585. c3.Ready += () => {
  586. Assert.Equal (3, Application.MdiChildes.Count);
  587. Application.Run (d1);
  588. };
  589. d1.Ready += () => {
  590. Assert.Equal (3, Application.MdiChildes.Count);
  591. Application.Run (d2);
  592. };
  593. d2.Ready += () => {
  594. Assert.Equal (3, Application.MdiChildes.Count);
  595. Assert.True (Application.Current == d2);
  596. Assert.True (Application.Current.Running);
  597. // Trying to close the Dialog1
  598. d1.RequestStop ();
  599. };
  600. // Now this will close the MdiContainer propagating through the MdiChildes.
  601. d1.Closed += (e) => {
  602. Assert.True (Application.Current == d1);
  603. Assert.False (Application.Current.Running);
  604. mdi.RequestStop ();
  605. };
  606. Application.Iteration += () => {
  607. if (iterations == 5) {
  608. // The Dialog2 still is the current top and we can't request stop to MdiContainer
  609. // because Dialog2 and Dialog1 must be closed first.
  610. // Dialog2 will be closed in this iteration.
  611. Assert.True (Application.Current == d2);
  612. Assert.False (Application.Current.Running);
  613. Assert.False (d1.Running);
  614. } else if (iterations == 4) {
  615. // Dialog1 will be closed in this iteration.
  616. Assert.True (Application.Current == d1);
  617. Assert.False (Application.Current.Running);
  618. } else {
  619. Assert.Equal (iterations, Application.MdiChildes.Count);
  620. for (int i = 0; i < iterations; i++) {
  621. Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  622. }
  623. }
  624. iterations--;
  625. };
  626. Application.Run (mdi);
  627. Assert.Empty (Application.MdiChildes);
  628. Application.Shutdown ();
  629. }
  630. [Fact]
  631. public void Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  632. {
  633. Init ();
  634. var mdi = new Mdi ();
  635. var c1 = new Toplevel ();
  636. var c2 = new Window ();
  637. var c3 = new Window ();
  638. var d1 = new Dialog ();
  639. var c4 = new Toplevel ();
  640. // MdiChild = c1, c2, c3, c4 = 4
  641. // d1 = 1
  642. var iterations = 5;
  643. mdi.Ready += () => {
  644. Assert.Empty (Application.MdiChildes);
  645. Application.Run (c1);
  646. };
  647. c1.Ready += () => {
  648. Assert.Single (Application.MdiChildes);
  649. Application.Run (c2);
  650. };
  651. c2.Ready += () => {
  652. Assert.Equal (2, Application.MdiChildes.Count);
  653. Application.Run (c3);
  654. };
  655. c3.Ready += () => {
  656. Assert.Equal (3, Application.MdiChildes.Count);
  657. Application.Run (d1);
  658. };
  659. d1.Ready += () => {
  660. Assert.Equal (3, Application.MdiChildes.Count);
  661. Application.Run (c4);
  662. };
  663. c4.Ready += () => {
  664. Assert.Equal (4, Application.MdiChildes.Count);
  665. // Trying to close the Dialog1
  666. d1.RequestStop ();
  667. };
  668. // Now this will close the MdiContainer propagating through the MdiChildes.
  669. d1.Closed += (e) => {
  670. mdi.RequestStop ();
  671. };
  672. Application.Iteration += () => {
  673. if (iterations == 5) {
  674. // The Dialog2 still is the current top and we can't request stop to MdiContainer
  675. // because Dialog2 and Dialog1 must be closed first.
  676. // Using request stop here will call the Dialog again without need
  677. Assert.True (Application.Current == d1);
  678. Assert.False (Application.Current.Running);
  679. Assert.True (c4.Running);
  680. } else {
  681. Assert.Equal (iterations, Application.MdiChildes.Count);
  682. for (int i = 0; i < iterations; i++) {
  683. Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
  684. Application.MdiChildes [i].Id);
  685. }
  686. }
  687. iterations--;
  688. };
  689. Application.Run (mdi);
  690. Assert.Empty (Application.MdiChildes);
  691. Application.Shutdown ();
  692. }
  693. [Fact]
  694. public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
  695. {
  696. Init ();
  697. var mdi = new Mdi ();
  698. var c1 = new Toplevel ();
  699. var c2 = new Window ();
  700. var c3 = new Window ();
  701. // MdiChild = c1, c2, c3
  702. var iterations = 3;
  703. mdi.Ready += () => {
  704. Assert.Empty (Application.MdiChildes);
  705. Application.Run (c1);
  706. };
  707. c1.Ready += () => {
  708. Assert.Single (Application.MdiChildes);
  709. Application.Run (c2);
  710. };
  711. c2.Ready += () => {
  712. Assert.Equal (2, Application.MdiChildes.Count);
  713. Application.Run (c3);
  714. };
  715. c3.Ready += () => {
  716. Assert.Equal (3, Application.MdiChildes.Count);
  717. c3.RequestStop ();
  718. c1.RequestStop ();
  719. };
  720. // Now this will close the MdiContainer propagating through the MdiChildes.
  721. c1.Closed += (e) => {
  722. mdi.RequestStop ();
  723. };
  724. Application.Iteration += () => {
  725. if (iterations == 3) {
  726. // The Current still is c3 because Current.Running is false.
  727. Assert.True (Application.Current == c3);
  728. Assert.False (Application.Current.Running);
  729. // But the childes order were reorder by Running = false
  730. Assert.True (Application.MdiChildes [0] == c3);
  731. Assert.True (Application.MdiChildes [1] == c1);
  732. Assert.True (Application.MdiChildes [^1] == c2);
  733. } else if (iterations == 2) {
  734. // The Current is c1 and Current.Running is false.
  735. Assert.True (Application.Current == c1);
  736. Assert.False (Application.Current.Running);
  737. Assert.True (Application.MdiChildes [0] == c1);
  738. Assert.True (Application.MdiChildes [^1] == c2);
  739. } else if (iterations == 1) {
  740. // The Current is c2 and Current.Running is false.
  741. Assert.True (Application.Current == c2);
  742. Assert.False (Application.Current.Running);
  743. Assert.True (Application.MdiChildes [^1] == c2);
  744. } else {
  745. // The Current is mdi.
  746. Assert.True (Application.Current == mdi);
  747. Assert.Empty (Application.MdiChildes);
  748. }
  749. iterations--;
  750. };
  751. Application.Run (mdi);
  752. Assert.Empty (Application.MdiChildes);
  753. Application.Shutdown ();
  754. }
  755. [Fact]
  756. public void MdiContainer_Throws_If_More_Than_One ()
  757. {
  758. Init ();
  759. var mdi = new Mdi ();
  760. var mdi2 = new Mdi ();
  761. mdi.Ready += () => {
  762. Assert.Throws<InvalidOperationException> (() => Application.Run (mdi2));
  763. mdi.RequestStop ();
  764. };
  765. Application.Run (mdi);
  766. Application.Shutdown ();
  767. }
  768. [Fact]
  769. public void MdiContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
  770. {
  771. Init ();
  772. var mdi = new Mdi ();
  773. var logger = new Toplevel ();
  774. var iterations = 1; // The logger
  775. var running = true;
  776. var stageCompleted = true;
  777. var allStageClosed = false;
  778. var mdiRequestStop = false;
  779. mdi.Ready += () => {
  780. Assert.Empty (Application.MdiChildes);
  781. Application.Run (logger);
  782. };
  783. logger.Ready += () => Assert.Single (Application.MdiChildes);
  784. Application.Iteration += () => {
  785. if (stageCompleted && running) {
  786. stageCompleted = false;
  787. var stage = new Window () { Modal = true };
  788. stage.Ready += () => {
  789. Assert.Equal (iterations, Application.MdiChildes.Count);
  790. stage.RequestStop ();
  791. };
  792. stage.Closed += (_) => {
  793. if (iterations == 11) {
  794. allStageClosed = true;
  795. }
  796. Assert.Equal (iterations, Application.MdiChildes.Count);
  797. if (running) {
  798. stageCompleted = true;
  799. var rpt = new Window ();
  800. rpt.Ready += () => {
  801. iterations++;
  802. Assert.Equal (iterations, Application.MdiChildes.Count);
  803. };
  804. Application.Run (rpt);
  805. }
  806. };
  807. Application.Run (stage);
  808. } else if (iterations == 11 && running) {
  809. running = false;
  810. Assert.Equal (iterations, Application.MdiChildes.Count);
  811. } else if (!mdiRequestStop && running && !allStageClosed) {
  812. Assert.Equal (iterations, Application.MdiChildes.Count);
  813. } else if (!mdiRequestStop && !running && allStageClosed) {
  814. Assert.Equal (iterations, Application.MdiChildes.Count);
  815. mdiRequestStop = true;
  816. mdi.RequestStop ();
  817. } else {
  818. Assert.Empty (Application.MdiChildes);
  819. }
  820. };
  821. Application.Run (mdi);
  822. Assert.Empty (Application.MdiChildes);
  823. Application.Shutdown ();
  824. }
  825. [Fact]
  826. public void AllChildClosed_Event_Test ()
  827. {
  828. Init ();
  829. var mdi = new Mdi ();
  830. var c1 = new Toplevel ();
  831. var c2 = new Window ();
  832. var c3 = new Window ();
  833. // MdiChild = c1, c2, c3
  834. var iterations = 3;
  835. mdi.Ready += () => {
  836. Assert.Empty (Application.MdiChildes);
  837. Application.Run (c1);
  838. };
  839. c1.Ready += () => {
  840. Assert.Single (Application.MdiChildes);
  841. Application.Run (c2);
  842. };
  843. c2.Ready += () => {
  844. Assert.Equal (2, Application.MdiChildes.Count);
  845. Application.Run (c3);
  846. };
  847. c3.Ready += () => {
  848. Assert.Equal (3, Application.MdiChildes.Count);
  849. c3.RequestStop ();
  850. c2.RequestStop ();
  851. c1.RequestStop ();
  852. };
  853. // Now this will close the MdiContainer when all MdiChildes was closed
  854. mdi.AllChildClosed += () => {
  855. mdi.RequestStop ();
  856. };
  857. Application.Iteration += () => {
  858. if (iterations == 3) {
  859. // The Current still is c3 because Current.Running is false.
  860. Assert.True (Application.Current == c3);
  861. Assert.False (Application.Current.Running);
  862. // But the childes order were reorder by Running = false
  863. Assert.True (Application.MdiChildes [0] == c3);
  864. Assert.True (Application.MdiChildes [1] == c2);
  865. Assert.True (Application.MdiChildes [^1] == c1);
  866. } else if (iterations == 2) {
  867. // The Current is c2 and Current.Running is false.
  868. Assert.True (Application.Current == c2);
  869. Assert.False (Application.Current.Running);
  870. Assert.True (Application.MdiChildes [0] == c2);
  871. Assert.True (Application.MdiChildes [^1] == c1);
  872. } else if (iterations == 1) {
  873. // The Current is c1 and Current.Running is false.
  874. Assert.True (Application.Current == c1);
  875. Assert.False (Application.Current.Running);
  876. Assert.True (Application.MdiChildes [^1] == c1);
  877. } else {
  878. // The Current is mdi.
  879. Assert.True (Application.Current == mdi);
  880. Assert.False (Application.Current.Running);
  881. Assert.Empty (Application.MdiChildes);
  882. }
  883. iterations--;
  884. };
  885. Application.Run (mdi);
  886. Assert.Empty (Application.MdiChildes);
  887. Application.Shutdown ();
  888. }
  889. [Fact]
  890. public void SetCurrentAsTop_Run_A_Not_Modal_Toplevel_Make_It_The_Current_Application_Top ()
  891. {
  892. Init ();
  893. var t1 = new Toplevel ();
  894. var t2 = new Toplevel ();
  895. var t3 = new Toplevel ();
  896. var d = new Dialog ();
  897. var t4 = new Toplevel ();
  898. // t1, t2, t3, d, t4
  899. var iterations = 5;
  900. t1.Ready += () => {
  901. Assert.Equal (t1, Application.Top);
  902. Application.Run (t2);
  903. };
  904. t2.Ready += () => {
  905. Assert.Equal (t2, Application.Top);
  906. Application.Run (t3);
  907. };
  908. t3.Ready += () => {
  909. Assert.Equal (t3, Application.Top);
  910. Application.Run (d);
  911. };
  912. d.Ready += () => {
  913. Assert.Equal (t3, Application.Top);
  914. Application.Run (t4);
  915. };
  916. t4.Ready += () => {
  917. Assert.Equal (t4, Application.Top);
  918. t4.RequestStop ();
  919. d.RequestStop ();
  920. t3.RequestStop ();
  921. t2.RequestStop ();
  922. };
  923. // Now this will close the MdiContainer when all MdiChildes was closed
  924. t2.Closed += (_) => {
  925. t1.RequestStop ();
  926. };
  927. Application.Iteration += () => {
  928. if (iterations == 5) {
  929. // The Current still is t4 because Current.Running is false.
  930. Assert.Equal (t4, Application.Current);
  931. Assert.False (Application.Current.Running);
  932. Assert.Equal (t4, Application.Top);
  933. } else if (iterations == 4) {
  934. // The Current is d and Current.Running is false.
  935. Assert.Equal (d, Application.Current);
  936. Assert.False (Application.Current.Running);
  937. Assert.Equal (t4, Application.Top);
  938. } else if (iterations == 3) {
  939. // The Current is t3 and Current.Running is false.
  940. Assert.Equal (t3, Application.Current);
  941. Assert.False (Application.Current.Running);
  942. Assert.Equal (t3, Application.Top);
  943. } else if (iterations == 2) {
  944. // The Current is t2 and Current.Running is false.
  945. Assert.Equal (t2, Application.Current);
  946. Assert.False (Application.Current.Running);
  947. Assert.Equal (t2, Application.Top);
  948. } else {
  949. // The Current is t1.
  950. Assert.Equal (t1, Application.Current);
  951. Assert.False (Application.Current.Running);
  952. Assert.Equal (t1, Application.Top);
  953. }
  954. iterations--;
  955. };
  956. Application.Run (t1);
  957. Assert.Equal (t1, Application.Top);
  958. Application.Shutdown ();
  959. Assert.Null (Application.Top);
  960. }
  961. [Fact]
  962. [AutoInitShutdown]
  963. public void Internal_Tests ()
  964. {
  965. Assert.True (Application._initialized);
  966. Assert.NotNull (Application.Top);
  967. var rs = Application.Begin (Application.Top);
  968. Assert.Equal (Application.Top, rs.Toplevel);
  969. Assert.Null (Application.mouseGrabView);
  970. Assert.Null (Application.wantContinuousButtonPressedView);
  971. Assert.False (Application.DebugDrawBounds);
  972. Assert.False (Application.ShowChild (Application.Top));
  973. Application.End (Application.Top);
  974. }
  975. [Fact]
  976. [AutoInitShutdown]
  977. public void QuitKey_Getter_Setter ()
  978. {
  979. var top = Application.Top;
  980. var isQuiting = false;
  981. top.Closing += (e) => {
  982. isQuiting = true;
  983. e.Cancel = true;
  984. };
  985. Application.Begin (top);
  986. top.Running = true;
  987. Assert.Equal (Key.Q | Key.CtrlMask, Application.QuitKey);
  988. Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true);
  989. Assert.True (isQuiting);
  990. isQuiting = false;
  991. Application.QuitKey = Key.C | Key.CtrlMask;
  992. Application.Driver.SendKeys ('q', ConsoleKey.Q, false, false, true);
  993. Assert.False (isQuiting);
  994. Application.Driver.SendKeys ('c', ConsoleKey.C, false, false, true);
  995. Assert.True (isQuiting);
  996. // Reset the QuitKey to avoid throws errors on another tests
  997. Application.QuitKey = Key.Q | Key.CtrlMask;
  998. }
  999. [Fact]
  1000. [AutoInitShutdown]
  1001. public void EnsuresTopOnFront_CanFocus_True_By_Keyboard_And_Mouse ()
  1002. {
  1003. var top = Application.Top;
  1004. var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 };
  1005. var tf = new TextField () { Width = 10 };
  1006. win.Add (tf);
  1007. var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 };
  1008. var tf2 = new TextField () { Width = 10 };
  1009. win2.Add (tf2);
  1010. top.Add (win, win2);
  1011. Application.Begin (top);
  1012. Assert.True (win.CanFocus);
  1013. Assert.True (win.HasFocus);
  1014. Assert.True (win2.CanFocus);
  1015. Assert.False (win2.HasFocus);
  1016. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1017. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  1018. Assert.True (win.CanFocus);
  1019. Assert.False (win.HasFocus);
  1020. Assert.True (win2.CanFocus);
  1021. Assert.True (win2.HasFocus);
  1022. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1023. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  1024. Assert.True (win.CanFocus);
  1025. Assert.True (win.HasFocus);
  1026. Assert.True (win2.CanFocus);
  1027. Assert.False (win2.HasFocus);
  1028. Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1029. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
  1030. Assert.True (win.CanFocus);
  1031. Assert.False (win.HasFocus);
  1032. Assert.True (win2.CanFocus);
  1033. Assert.True (win2.HasFocus);
  1034. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1035. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
  1036. Assert.Null (Toplevel.dragPosition);
  1037. }
  1038. [Fact]
  1039. [AutoInitShutdown]
  1040. public void EnsuresTopOnFront_CanFocus_False_By_Keyboard_And_Mouse ()
  1041. {
  1042. var top = Application.Top;
  1043. var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 };
  1044. var tf = new TextField () { Width = 10 };
  1045. win.Add (tf);
  1046. var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 };
  1047. var tf2 = new TextField () { Width = 10 };
  1048. win2.Add (tf2);
  1049. top.Add (win, win2);
  1050. Application.Begin (top);
  1051. Assert.True (win.CanFocus);
  1052. Assert.True (win.HasFocus);
  1053. Assert.True (win2.CanFocus);
  1054. Assert.False (win2.HasFocus);
  1055. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1056. win.CanFocus = false;
  1057. Assert.False (win.CanFocus);
  1058. Assert.False (win.HasFocus);
  1059. Assert.True (win2.CanFocus);
  1060. Assert.True (win2.HasFocus);
  1061. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1062. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  1063. Assert.True (win2.CanFocus);
  1064. Assert.False (win.HasFocus);
  1065. Assert.True (win2.CanFocus);
  1066. Assert.True (win2.HasFocus);
  1067. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1068. top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
  1069. Assert.False (win.CanFocus);
  1070. Assert.False (win.HasFocus);
  1071. Assert.True (win2.CanFocus);
  1072. Assert.True (win2.HasFocus);
  1073. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1074. win.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
  1075. Assert.False (win.CanFocus);
  1076. Assert.False (win.HasFocus);
  1077. Assert.True (win2.CanFocus);
  1078. Assert.True (win2.HasFocus);
  1079. Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
  1080. win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
  1081. Assert.Null (Toplevel.dragPosition);
  1082. }
  1083. [Fact, AutoInitShutdown]
  1084. public void GetSupportedCultures_Method ()
  1085. {
  1086. var cultures = Application.GetSupportedCultures ();
  1087. Assert.Equal (cultures.Count, Application.SupportedCultures.Count);
  1088. }
  1089. [Fact, AutoInitShutdown]
  1090. public void TestAddManyTimeouts ()
  1091. {
  1092. int delegatesRun = 0;
  1093. int numberOfThreads = 100;
  1094. int numberOfTimeoutsPerThread = 100;
  1095. // start lots of threads
  1096. for (int i = 0; i < numberOfThreads; i++) {
  1097. var myi = i;
  1098. Task.Run (() => {
  1099. Task.Delay (100).Wait ();
  1100. // each thread registers lots of 1s timeouts
  1101. for(int j=0;j< numberOfTimeoutsPerThread; j++) {
  1102. Application.MainLoop.AddTimeout (TimeSpan.FromSeconds(1), (s) => {
  1103. // each timeout delegate increments delegatesRun count by 1 every second
  1104. Interlocked.Increment (ref delegatesRun);
  1105. return true;
  1106. });
  1107. }
  1108. // if this is the first Thread created
  1109. if (myi == 0) {
  1110. // let the timeouts run for a bit
  1111. Task.Delay (5000).Wait ();
  1112. // then tell the application to quuit
  1113. Application.MainLoop.Invoke (() => Application.RequestStop ());
  1114. }
  1115. });
  1116. }
  1117. // blocks here until the RequestStop is processed at the end of the test
  1118. Application.Run ();
  1119. // undershoot a bit to be on the safe side. The 5000 ms wait allows the timeouts to run
  1120. // a lot but all those timeout delegates could end up going slowly on a slow machine perhaps
  1121. // so the final number of delegatesRun might vary by computer. So for this assert we say
  1122. // that it should have run at least 2 seconds worth of delegates
  1123. Assert.True (delegatesRun >= numberOfThreads * numberOfTimeoutsPerThread * 2);
  1124. }
  1125. }
  1126. }