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