ApplicationTests.cs 38 KB

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