OverlappedTests.cs 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  1. #nullable enable
  2. using System.Threading;
  3. using JetBrains.Annotations;
  4. using Xunit.Abstractions;
  5. namespace Terminal.Gui.ViewsTests;
  6. public class OverlappedTests
  7. {
  8. private readonly ITestOutputHelper _output;
  9. public OverlappedTests (ITestOutputHelper output)
  10. {
  11. _output = output;
  12. #if DEBUG_IDISPOSABLE
  13. Responder.Instances.Clear ();
  14. RunState.Instances.Clear ();
  15. #endif
  16. }
  17. [Fact]
  18. [AutoInitShutdown]
  19. public void AllChildClosed_Event_Test ()
  20. {
  21. var overlapped = new Overlapped ();
  22. var c1 = new Toplevel ();
  23. var c2 = new Window ();
  24. var c3 = new Window ();
  25. // OverlappedChild = c1, c2, c3
  26. var iterations = 3;
  27. overlapped.Ready += (s, e) =>
  28. {
  29. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  30. Application.Run (c1);
  31. };
  32. c1.Ready += (s, e) =>
  33. {
  34. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  35. Application.Run (c2);
  36. };
  37. c2.Ready += (s, e) =>
  38. {
  39. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  40. Application.Run (c3);
  41. };
  42. c3.Ready += (s, e) =>
  43. {
  44. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  45. c3.RequestStop ();
  46. c2.RequestStop ();
  47. c1.RequestStop ();
  48. };
  49. // Now this will close the OverlappedContainer when all OverlappedChildren was closed
  50. overlapped.AllChildClosed += (s, e) => { overlapped.RequestStop (); };
  51. Application.Iteration += (s, a) =>
  52. {
  53. if (iterations == 3)
  54. {
  55. // The Current still is c3 because Current.Running is false.
  56. Assert.True (Application.Current == c3);
  57. Assert.False (Application.Current.Running);
  58. // But the Children order were reorder by Running = false
  59. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c3);
  60. Assert.True (ApplicationOverlapped.OverlappedChildren [1] == c2);
  61. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c1);
  62. }
  63. else if (iterations == 2)
  64. {
  65. // The Current is c2 and Current.Running is false.
  66. Assert.True (Application.Current == c2);
  67. Assert.False (Application.Current.Running);
  68. Assert.True (ApplicationOverlapped.OverlappedChildren ![0] == c2);
  69. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c1);
  70. }
  71. else if (iterations == 1)
  72. {
  73. // The Current is c1 and Current.Running is false.
  74. Assert.True (Application.Current == c1);
  75. Assert.False (Application.Current.Running);
  76. Assert.True (ApplicationOverlapped.OverlappedChildren! [^1] == c1);
  77. }
  78. else
  79. {
  80. // The Current is overlapped.
  81. Assert.True (Application.Current == overlapped);
  82. Assert.False (Application.Current.Running);
  83. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  84. }
  85. iterations--;
  86. };
  87. Application.Run (overlapped);
  88. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  89. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  90. Assert.NotNull (Application.Top);
  91. overlapped.Dispose ();
  92. }
  93. [Fact]
  94. [AutoInitShutdown]
  95. public void Application_RequestStop_With_Params_On_A_Not_OverlappedContainer_Always_Use_Application_Current ()
  96. {
  97. var top1 = new Toplevel ();
  98. var top2 = new Toplevel ();
  99. var top3 = new Window ();
  100. var top4 = new Window ();
  101. var d = new Dialog ();
  102. // top1, top2, top3, d1 = 4
  103. var iterations = 4;
  104. top1.Ready += (s, e) =>
  105. {
  106. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  107. Application.Run (top2);
  108. };
  109. top2.Ready += (s, e) =>
  110. {
  111. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  112. Application.Run (top3);
  113. };
  114. top3.Ready += (s, e) =>
  115. {
  116. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  117. Application.Run (top4);
  118. };
  119. top4.Ready += (s, e) =>
  120. {
  121. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  122. Application.Run (d);
  123. };
  124. d.Ready += (s, e) =>
  125. {
  126. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  127. // This will close the d because on a not OverlappedContainer the Application.Current it always used.
  128. Application.RequestStop (top1);
  129. Assert.True (Application.Current == d);
  130. };
  131. d.Closed += (s, e) => Application.RequestStop (top1);
  132. Application.Iteration += (s, a) =>
  133. {
  134. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  135. if (iterations == 4)
  136. {
  137. Assert.True (Application.Current == d);
  138. }
  139. else if (iterations == 3)
  140. {
  141. Assert.True (Application.Current == top4);
  142. }
  143. else if (iterations == 2)
  144. {
  145. Assert.True (Application.Current == top3);
  146. }
  147. else if (iterations == 1)
  148. {
  149. Assert.True (Application.Current == top2);
  150. }
  151. else
  152. {
  153. Assert.True (Application.Current == top1);
  154. }
  155. Application.RequestStop (top1);
  156. iterations--;
  157. };
  158. Application.Run (top1);
  159. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  160. top1.Dispose ();
  161. }
  162. [Fact]
  163. [TestRespondersDisposed]
  164. public void Dispose_Toplevel_IsOverlappedContainer_False_With_Begin_End ()
  165. {
  166. Application.Init (new FakeDriver ());
  167. var top = new Toplevel ();
  168. RunState rs = Application.Begin (top);
  169. Application.End (rs);
  170. top.Dispose ();
  171. Application.Shutdown ();
  172. #if DEBUG_IDISPOSABLE
  173. Assert.Empty (Responder.Instances);
  174. #endif
  175. }
  176. [Fact]
  177. [TestRespondersDisposed]
  178. public void Dispose_Toplevel_IsOverlappedContainer_True_With_Begin ()
  179. {
  180. Application.Init (new FakeDriver ());
  181. var overlapped = new Toplevel { IsOverlappedContainer = true };
  182. RunState rs = Application.Begin (overlapped);
  183. Application.End (rs);
  184. overlapped.Dispose ();
  185. Application.Shutdown ();
  186. }
  187. [Fact]
  188. [AutoInitShutdown]
  189. public void IsOverlappedChild_Testing ()
  190. {
  191. var overlapped = new Overlapped ();
  192. var c1 = new Toplevel ();
  193. var c2 = new Window ();
  194. var c3 = new Window ();
  195. var d = new Dialog ();
  196. Application.Iteration += (s, a) =>
  197. {
  198. Assert.False (ApplicationOverlapped.IsOverlapped(overlapped));
  199. Assert.True (ApplicationOverlapped.IsOverlapped(c1));
  200. Assert.True (ApplicationOverlapped.IsOverlapped(c2));
  201. Assert.True (ApplicationOverlapped.IsOverlapped(c3));
  202. Assert.False (ApplicationOverlapped.IsOverlapped(d));
  203. overlapped.RequestStop ();
  204. };
  205. Application.Run (overlapped);
  206. overlapped.Dispose ();
  207. }
  208. [Fact]
  209. [AutoInitShutdown]
  210. public void
  211. Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  212. {
  213. var overlapped = new Overlapped ();
  214. var c1 = new Toplevel ();
  215. var c2 = new Window ();
  216. var c3 = new Window ();
  217. var d1 = new Dialog ();
  218. var d2 = new Dialog ();
  219. // OverlappedChild = c1, c2, c3 = 3
  220. // d1, d2 = 2
  221. var iterations = 5;
  222. overlapped.Ready += (s, e) =>
  223. {
  224. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  225. Application.Run (c1);
  226. };
  227. c1.Ready += (s, e) =>
  228. {
  229. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  230. Application.Run (c2);
  231. };
  232. c2.Ready += (s, e) =>
  233. {
  234. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  235. Application.Run (c3);
  236. };
  237. c3.Ready += (s, e) =>
  238. {
  239. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  240. Application.Run (d1);
  241. };
  242. d1.Ready += (s, e) =>
  243. {
  244. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  245. Application.Run (d2);
  246. };
  247. d2.Ready += (s, e) =>
  248. {
  249. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  250. Assert.True (Application.Current == d2);
  251. Assert.True (Application.Current.Running);
  252. // Trying to close the Dialog1
  253. d1.RequestStop ();
  254. };
  255. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  256. d1.Closed += (s, e) =>
  257. {
  258. Assert.True (Application.Current == d1);
  259. Assert.False (Application.Current.Running);
  260. overlapped.RequestStop ();
  261. };
  262. Application.Iteration += (s, a) =>
  263. {
  264. if (iterations == 5)
  265. {
  266. // The Dialog2 still is the current top and we can't request stop to OverlappedContainer
  267. // because Dialog2 and Dialog1 must be closed first.
  268. // Dialog2 will be closed in this iteration.
  269. Assert.True (Application.Current == d2);
  270. Assert.False (Application.Current.Running);
  271. Assert.False (d1.Running);
  272. }
  273. else if (iterations == 4)
  274. {
  275. // Dialog1 will be closed in this iteration.
  276. Assert.True (Application.Current == d1);
  277. Assert.False (Application.Current.Running);
  278. }
  279. else
  280. {
  281. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  282. for (var i = 0; i < iterations; i++)
  283. {
  284. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  285. }
  286. }
  287. iterations--;
  288. };
  289. Application.Run (overlapped);
  290. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  291. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  292. Assert.NotNull (Application.Top);
  293. overlapped.Dispose ();
  294. }
  295. [Fact]
  296. [AutoInitShutdown]
  297. public void
  298. Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  299. {
  300. var overlapped = new Overlapped ();
  301. var c1 = new Toplevel ();
  302. var c2 = new Window ();
  303. var c3 = new Window ();
  304. var d1 = new Dialog ();
  305. var c4 = new Toplevel ();
  306. // OverlappedChild = c1, c2, c3, c4 = 4
  307. // d1 = 1
  308. var iterations = 5;
  309. overlapped.Ready += (s, e) =>
  310. {
  311. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  312. Application.Run (c1);
  313. };
  314. c1.Ready += (s, e) =>
  315. {
  316. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  317. Application.Run (c2);
  318. };
  319. c2.Ready += (s, e) =>
  320. {
  321. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  322. Application.Run (c3);
  323. };
  324. c3.Ready += (s, e) =>
  325. {
  326. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  327. Application.Run (d1);
  328. };
  329. d1.Ready += (s, e) =>
  330. {
  331. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  332. Application.Run (c4);
  333. };
  334. c4.Ready += (s, e) =>
  335. {
  336. Assert.Equal (4, ApplicationOverlapped.OverlappedChildren!.Count);
  337. // Trying to close the Dialog1
  338. d1.RequestStop ();
  339. };
  340. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  341. d1.Closed += (s, e) => { overlapped.RequestStop (); };
  342. Application.Iteration += (s, a) =>
  343. {
  344. if (iterations == 5)
  345. {
  346. // The Dialog2 still is the current top and we can't request stop to OverlappedContainer
  347. // because Dialog2 and Dialog1 must be closed first.
  348. // Using request stop here will call the Dialog again without need
  349. Assert.True (Application.Current == d1);
  350. Assert.False (Application.Current.Running);
  351. Assert.True (c4.Running);
  352. }
  353. else
  354. {
  355. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  356. for (var i = 0; i < iterations; i++)
  357. {
  358. Assert.Equal (
  359. (iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
  360. ApplicationOverlapped.OverlappedChildren [i].Id
  361. );
  362. }
  363. }
  364. iterations--;
  365. };
  366. Application.Run (overlapped);
  367. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  368. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  369. Assert.NotNull (Application.Top);
  370. overlapped.Dispose ();
  371. }
  372. [Fact]
  373. [AutoInitShutdown]
  374. public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
  375. {
  376. Overlapped? overlapped = new Overlapped ();
  377. var c1 = new Toplevel ();
  378. var c2 = new Window ();
  379. var c3 = new Window ();
  380. // OverlappedChild = c1, c2, c3
  381. var iterations = 3;
  382. overlapped.Ready += (s, e) =>
  383. {
  384. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  385. Application.Run (c1);
  386. };
  387. c1.Ready += (s, e) =>
  388. {
  389. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  390. Application.Run (c2);
  391. };
  392. c2.Ready += (s, e) =>
  393. {
  394. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  395. Application.Run (c3);
  396. };
  397. c3.Ready += (s, e) =>
  398. {
  399. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  400. c3.RequestStop ();
  401. c1.RequestStop ();
  402. };
  403. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  404. c1.Closed += (s, e) => { overlapped.RequestStop (); };
  405. Application.Iteration += (s, a) =>
  406. {
  407. if (iterations == 3)
  408. {
  409. // The Current still is c3 because Current.Running is false.
  410. Assert.True (Application.Current == c3);
  411. Assert.False (Application.Current.Running);
  412. // But the Children order were reorder by Running = false
  413. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c3);
  414. Assert.True (ApplicationOverlapped.OverlappedChildren [1] == c1);
  415. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c2);
  416. }
  417. else if (iterations == 2)
  418. {
  419. // The Current is c1 and Current.Running is false.
  420. Assert.True (Application.Current == c1);
  421. Assert.False (Application.Current.Running);
  422. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c1);
  423. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c2);
  424. }
  425. else if (iterations == 1)
  426. {
  427. // The Current is c2 and Current.Running is false.
  428. Assert.True (Application.Current == c2);
  429. Assert.False (Application.Current.Running);
  430. Assert.True (ApplicationOverlapped.OverlappedChildren! [^1] == c2);
  431. }
  432. else
  433. {
  434. // The Current is overlapped.
  435. Assert.True (Application.Current == overlapped);
  436. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  437. }
  438. iterations--;
  439. };
  440. Application.Run (overlapped);
  441. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  442. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  443. Assert.NotNull (Application.Top);
  444. overlapped.Dispose ();
  445. }
  446. [Fact]
  447. public void MoveToOverlappedChild_Throw_NullReferenceException_Passing_Null_Parameter ()
  448. {
  449. Assert.Throws<ArgumentNullException> (delegate { ApplicationOverlapped.MoveToOverlappedChild (null); });
  450. }
  451. [Fact]
  452. [AutoInitShutdown]
  453. public void OverlappedContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
  454. {
  455. var overlapped = new Overlapped ();
  456. var logger = new Toplevel ();
  457. var iterations = 1; // The logger
  458. var running = true;
  459. var stageCompleted = true;
  460. var allStageClosed = false;
  461. var overlappedRequestStop = false;
  462. overlapped.Ready += (s, e) =>
  463. {
  464. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  465. Application.Run (logger);
  466. };
  467. logger.Ready += (s, e) => Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  468. Application.Iteration += (s, a) =>
  469. {
  470. if (stageCompleted && running)
  471. {
  472. stageCompleted = false;
  473. var stage = new Window { Modal = true };
  474. stage.Ready += (s, e) =>
  475. {
  476. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  477. stage.RequestStop ();
  478. };
  479. stage.Closed += (_, _) =>
  480. {
  481. if (iterations == 11)
  482. {
  483. allStageClosed = true;
  484. }
  485. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  486. if (running)
  487. {
  488. stageCompleted = true;
  489. var rpt = new Window ();
  490. rpt.Ready += (s, e) =>
  491. {
  492. iterations++;
  493. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren.Count);
  494. };
  495. Application.Run (rpt);
  496. }
  497. };
  498. Application.Run (stage);
  499. }
  500. else if (iterations == 11 && running)
  501. {
  502. running = false;
  503. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  504. }
  505. else if (!overlappedRequestStop && running && !allStageClosed)
  506. {
  507. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  508. }
  509. else if (!overlappedRequestStop && !running && allStageClosed)
  510. {
  511. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  512. overlappedRequestStop = true;
  513. overlapped?.RequestStop ();
  514. }
  515. else
  516. {
  517. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  518. }
  519. };
  520. Application.Run (overlapped);
  521. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  522. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  523. Assert.NotNull (Application.Top);
  524. overlapped.Dispose ();
  525. }
  526. [Fact]
  527. [AutoInitShutdown]
  528. public void OverlappedContainer_Throws_If_More_Than_One ()
  529. {
  530. var overlapped = new Overlapped ();
  531. var overlapped2 = new Overlapped ();
  532. overlapped.Ready += (s, e) =>
  533. {
  534. Assert.Throws<InvalidOperationException> (() => Application.Run (overlapped2));
  535. overlapped.RequestStop ();
  536. };
  537. Application.Run (overlapped);
  538. overlapped.Dispose ();
  539. }
  540. [Fact]
  541. [AutoInitShutdown]
  542. public void OverlappedContainer_With_Application_RequestStop_OverlappedTop_With_Params ()
  543. {
  544. var overlapped = new Overlapped ();
  545. var c1 = new Toplevel ();
  546. var c2 = new Window ();
  547. var c3 = new Window ();
  548. var d = new Dialog ();
  549. // OverlappedChild = c1, c2, c3
  550. // d1 = 1
  551. var iterations = 4;
  552. overlapped.Ready += (s, e) =>
  553. {
  554. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  555. Application.Run (c1);
  556. };
  557. c1.Ready += (s, e) =>
  558. {
  559. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  560. Application.Run (c2);
  561. };
  562. c2.Ready += (s, e) =>
  563. {
  564. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  565. Application.Run (c3);
  566. };
  567. c3.Ready += (s, e) =>
  568. {
  569. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  570. Application.Run (d);
  571. };
  572. // Also easy because the Overlapped Container handles all at once
  573. d.Ready += (s, e) =>
  574. {
  575. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  576. // This will not close the OverlappedContainer because d is a modal Toplevel
  577. Application.RequestStop (overlapped);
  578. };
  579. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  580. d.Closed += (s, e) => Application.RequestStop (overlapped);
  581. Application.Iteration += (s, a) =>
  582. {
  583. if (iterations == 4)
  584. {
  585. // The Dialog was not closed before and will be closed now.
  586. Assert.True (Application.Current == d);
  587. Assert.False (d.Running);
  588. }
  589. else
  590. {
  591. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  592. for (var i = 0; i < iterations; i++)
  593. {
  594. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  595. }
  596. }
  597. iterations--;
  598. };
  599. Application.Run (overlapped);
  600. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  601. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  602. Assert.NotNull (Application.Top);
  603. overlapped.Dispose ();
  604. }
  605. [Fact]
  606. [AutoInitShutdown]
  607. public void OverlappedContainer_With_Application_RequestStop_OverlappedTop_Without_Params ()
  608. {
  609. var overlapped = new Overlapped ();
  610. var c1 = new Toplevel ();
  611. var c2 = new Window ();
  612. var c3 = new Window ();
  613. var d = new Dialog ();
  614. // OverlappedChild = c1, c2, c3 = 3
  615. // d1 = 1
  616. var iterations = 4;
  617. overlapped.Ready += (s, e) =>
  618. {
  619. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  620. Application.Run (c1);
  621. };
  622. c1.Ready += (s, e) =>
  623. {
  624. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  625. Application.Run (c2);
  626. };
  627. c2.Ready += (s, e) =>
  628. {
  629. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  630. Application.Run (c3);
  631. };
  632. c3.Ready += (s, e) =>
  633. {
  634. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  635. Application.Run (d);
  636. };
  637. //More harder because it's sequential.
  638. d.Ready += (s, e) =>
  639. {
  640. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  641. // Close the Dialog
  642. Application.RequestStop ();
  643. };
  644. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  645. d.Closed += (s, e) => Application.RequestStop (overlapped);
  646. Application.Iteration += (s, a) =>
  647. {
  648. if (iterations == 4)
  649. {
  650. // The Dialog still is the current top and we can't request stop to OverlappedContainer
  651. // because we are not using parameter calls.
  652. Assert.True (Application.Current == d);
  653. Assert.False (d.Running);
  654. }
  655. else
  656. {
  657. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  658. for (var i = 0; i < iterations; i++)
  659. {
  660. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  661. }
  662. }
  663. iterations--;
  664. };
  665. Application.Run (overlapped);
  666. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  667. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  668. Assert.NotNull (Application.Top);
  669. overlapped.Dispose ();
  670. }
  671. [Fact]
  672. [AutoInitShutdown]
  673. public void OverlappedContainer_With_Toplevel_RequestStop_Balanced ()
  674. {
  675. var overlapped = new Overlapped ();
  676. var c1 = new Toplevel ();
  677. var c2 = new Window ();
  678. var c3 = new Window ();
  679. var d = new Dialog ();
  680. // OverlappedChild = c1, c2, c3
  681. // d1 = 1
  682. var iterations = 4;
  683. overlapped.Ready += (s, e) =>
  684. {
  685. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  686. Application.Run (c1);
  687. };
  688. c1.Ready += (s, e) =>
  689. {
  690. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  691. Application.Run (c2);
  692. };
  693. c2.Ready += (s, e) =>
  694. {
  695. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  696. Application.Run (c3);
  697. };
  698. c3.Ready += (s, e) =>
  699. {
  700. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  701. Application.Run (d);
  702. };
  703. // More easy because the Overlapped Container handles all at once
  704. d.Ready += (s, e) =>
  705. {
  706. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  707. // This will not close the OverlappedContainer because d is a modal Toplevel and will be closed.
  708. overlapped.RequestStop ();
  709. };
  710. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  711. d.Closed += (s, e) => { overlapped.RequestStop (); };
  712. Application.Iteration += (s, a) =>
  713. {
  714. if (iterations == 4)
  715. {
  716. // The Dialog was not closed before and will be closed now.
  717. Assert.True (Application.Current == d);
  718. Assert.False (d.Running);
  719. }
  720. else
  721. {
  722. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  723. for (var i = 0; i < iterations; i++)
  724. {
  725. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  726. }
  727. }
  728. iterations--;
  729. };
  730. Application.Run (overlapped);
  731. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  732. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  733. Assert.NotNull (Application.Top);
  734. overlapped.Dispose ();
  735. }
  736. [Fact]
  737. [AutoInitShutdown]
  738. public void Visible_False_Does_Not_Clear ()
  739. {
  740. var overlapped = new Overlapped ();
  741. var win1 = new Window { Width = 5, Height = 5, Visible = false };
  742. var win2 = new Window { X = 1, Y = 1, Width = 5, Height = 5 };
  743. ((FakeDriver)Application.Driver!).SetBufferSize (10, 10);
  744. RunState rsOverlapped = Application.Begin (overlapped);
  745. // Need to fool MainLoop into thinking it's running
  746. Application.MainLoop!.Running = true;
  747. // RunIteration must be call on each iteration because
  748. // it's using the Begin and not the Run method
  749. var firstIteration = false;
  750. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  751. Assert.Equal (overlapped, rsOverlapped.Toplevel);
  752. Assert.Equal (Application.Top, rsOverlapped.Toplevel);
  753. Assert.Equal (ApplicationOverlapped.OverlappedTop, rsOverlapped.Toplevel);
  754. Assert.Equal (Application.Current, rsOverlapped.Toplevel);
  755. Assert.Equal (overlapped, Application.Current);
  756. RunState rsWin1 = Application.Begin (win1);
  757. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  758. Assert.Equal (overlapped, rsOverlapped.Toplevel);
  759. Assert.Equal (Application.Top, rsOverlapped.Toplevel);
  760. Assert.Equal (ApplicationOverlapped.OverlappedTop, rsOverlapped.Toplevel);
  761. // The win1 Visible is false and cannot be set as the Current
  762. Assert.Equal (Application.Current, rsOverlapped.Toplevel);
  763. Assert.Equal (overlapped, Application.Current);
  764. Assert.Equal (win1, rsWin1.Toplevel);
  765. RunState rsWin2 = Application.Begin (win2);
  766. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  767. // Here the Current and the rsOverlapped.Toplevel is now the win2
  768. // and not the original overlapped
  769. Assert.Equal (win2, rsOverlapped.Toplevel);
  770. Assert.Equal (Application.Top, overlapped);
  771. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  772. Assert.Equal (Application.Current, rsWin2.Toplevel);
  773. Assert.Equal (win2, Application.Current);
  774. Assert.Equal (win1, rsWin1.Toplevel);
  775. // Tests that rely on visuals are too fragile. If border style changes they break.
  776. // Instead we should just rely on the test above.
  777. Application.OnMouseEvent (new MouseEvent { Position = new (1, 1), Flags = MouseFlags.Button1Pressed });
  778. Assert.Equal (win2.Border, Application.MouseGrabView);
  779. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  780. Assert.Equal (win2, rsOverlapped.Toplevel);
  781. Assert.Equal (Application.Top, overlapped);
  782. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  783. Assert.Equal (Application.Current, rsWin2.Toplevel);
  784. Assert.Equal (win2, Application.Current);
  785. Assert.Equal (win1, rsWin1.Toplevel);
  786. Application.OnMouseEvent (new MouseEvent
  787. {
  788. Position = new (2, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  789. });
  790. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  791. Assert.Equal (win2, rsOverlapped.Toplevel);
  792. Assert.Equal (Application.Top, overlapped);
  793. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  794. Assert.Equal (Application.Current, rsWin2.Toplevel);
  795. Assert.Equal (win2, Application.Current);
  796. Assert.Equal (win1, rsWin1.Toplevel);
  797. // Tests that rely on visuals are too fragile. If border style changes they break.
  798. // Instead we should just rely on the test above.
  799. // This will end the win2 and not the overlapped
  800. Application.End (rsOverlapped);
  801. // rsOverlapped has been disposed and Toplevel property is null
  802. // So we must use another valid RunState to iterate
  803. Application.RunIteration (ref rsWin1, ref firstIteration);
  804. #if DEBUG_IDISPOSABLE
  805. Assert.True (rsOverlapped.WasDisposed);
  806. #endif
  807. Assert.Null (rsOverlapped.Toplevel);
  808. Assert.Equal (Application.Top, overlapped);
  809. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  810. Assert.Equal (Application.Current, rsWin1.Toplevel);
  811. Assert.Equal (win1, Application.Current);
  812. Assert.Equal (win1, rsWin1.Toplevel);
  813. Application.End (rsWin1);
  814. // rsWin1 has been disposed and Toplevel property is null
  815. // So we must use another valid RunState to iterate
  816. Application.RunIteration (ref rsWin2, ref firstIteration);
  817. #if DEBUG_IDISPOSABLE
  818. Assert.True (rsOverlapped.WasDisposed);
  819. Assert.True (rsWin1.WasDisposed);
  820. #endif
  821. Assert.Null (rsOverlapped.Toplevel);
  822. Assert.Equal (Application.Top, overlapped);
  823. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  824. Assert.Equal (Application.Current, overlapped);
  825. Assert.Null (rsWin1.Toplevel);
  826. // See here that the only Toplevel that needs to End is the overlapped
  827. // which the rsWin2 now has the Toplevel set to the overlapped
  828. Assert.Equal (overlapped, rsWin2.Toplevel);
  829. Application.End (rsWin2);
  830. // There is no more RunState to iteration
  831. #if DEBUG_IDISPOSABLE
  832. Assert.True (rsOverlapped.WasDisposed);
  833. Assert.True (rsWin1.WasDisposed);
  834. Assert.True (rsWin2.WasDisposed);
  835. #endif
  836. Assert.Null (rsOverlapped.Toplevel);
  837. Assert.Equal (Application.Top, overlapped);
  838. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  839. Assert.Null (Application.Current);
  840. Assert.Null (rsWin1.Toplevel);
  841. Assert.Null (rsWin2.Toplevel);
  842. #if DEBUG_IDISPOSABLE
  843. Assert.False (win2.WasDisposed);
  844. Assert.False (win1.WasDisposed);
  845. Assert.False (overlapped.WasDisposed);
  846. #endif
  847. // Now dispose all them
  848. win2.Dispose ();
  849. win1.Dispose ();
  850. overlapped.Dispose ();
  851. Application.Shutdown ();
  852. }
  853. private class Overlapped : Toplevel
  854. {
  855. public Overlapped () { IsOverlappedContainer = true; }
  856. }
  857. [Fact (Skip = "#2491: This test is really bogus. It does things like Runnable = false and is overly convolulted. Replace.")]
  858. [AutoInitShutdown]
  859. public void KeyBindings_Command_With_OverlappedTop ()
  860. {
  861. Toplevel top = new ();
  862. Assert.Null (ApplicationOverlapped.OverlappedTop);
  863. top.IsOverlappedContainer = true;
  864. Application.Begin (top);
  865. Assert.Equal (Application.Top, ApplicationOverlapped.OverlappedTop);
  866. var isRunning = true;
  867. var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
  868. var lblTf1W1 = new Label { Text = "Enter text in TextField on Win1:" };
  869. var tf1W1 = new TextField { Id="tf1W1", X = Pos.Right (lblTf1W1) + 1, Width = Dim.Fill (), Text = "Text1 on Win1" };
  870. var lblTvW1 = new Label { Y = Pos.Bottom (lblTf1W1) + 1, Text = "Enter text in TextView on Win1:" };
  871. var tvW1 = new TextView
  872. {
  873. Id = "tvW1",
  874. X = Pos.Left (tf1W1), Width = Dim.Fill (), Height = 2, Text = "First line Win1\nSecond line Win1"
  875. };
  876. var lblTf2W1 = new Label { Y = Pos.Bottom (lblTvW1) + 1, Text = "Enter text in TextField on Win1:" };
  877. var tf2W1 = new TextField { Id = "tf2W1", X = Pos.Left (tf1W1), Width = Dim.Fill (), Text = "Text2 on Win1" };
  878. win1.Add (lblTf1W1, tf1W1, lblTvW1, tvW1, lblTf2W1, tf2W1);
  879. var win2 = new Window { Id = "win2", Width = Dim.Percent (50), Height = Dim.Fill () };
  880. var lblTf1W2 = new Label { Text = "Enter text in TextField on Win2:" };
  881. var tf1W2 = new TextField { Id = "tf1W2", X = Pos.Right (lblTf1W2) + 1, Width = Dim.Fill (), Text = "Text1 on Win2" };
  882. var lblTvW2 = new Label { Y = Pos.Bottom (lblTf1W2) + 1, Text = "Enter text in TextView on Win2:" };
  883. var tvW2 = new TextView
  884. {
  885. Id = "tvW2",
  886. X = Pos.Left (tf1W2), Width = Dim.Fill (), Height = 2, Text = "First line Win1\nSecond line Win2"
  887. };
  888. var lblTf2W2 = new Label { Y = Pos.Bottom (lblTvW2) + 1, Text = "Enter text in TextField on Win2:" };
  889. var tf2W2 = new TextField { Id = "tf2W2", X = Pos.Left (tf1W2), Width = Dim.Fill (), Text = "Text2 on Win2" };
  890. win2.Add (lblTf1W2, tf1W2, lblTvW2, tvW2, lblTf2W2, tf2W2);
  891. win1.Closing += (s, e) => isRunning = false;
  892. Assert.Null (top.Focused);
  893. Assert.Equal (top, Application.Current);
  894. Assert.True (top.IsCurrentTop);
  895. Assert.Equal (top, ApplicationOverlapped.OverlappedTop);
  896. Application.Begin (win1);
  897. Assert.Equal (new (0, 0, 40, 25), win1.Frame);
  898. Assert.NotEqual (top, Application.Current);
  899. Assert.False (top.IsCurrentTop);
  900. Assert.Equal (win1, Application.Current);
  901. Assert.True (win1.IsCurrentTop);
  902. Assert.True (ApplicationOverlapped.IsOverlapped(win1));
  903. Assert.Null (top.Focused);
  904. Assert.Null (top.MostFocused);
  905. Assert.Equal (tf1W1, win1.MostFocused);
  906. Assert.True (ApplicationOverlapped.IsOverlapped(win1));
  907. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  908. Application.Begin (win2);
  909. Assert.Equal (new (0, 0, 40, 25), win2.Frame);
  910. Assert.NotEqual (top, Application.Current);
  911. Assert.False (top.IsCurrentTop);
  912. Assert.Equal (win2, Application.Current);
  913. Assert.True (win2.IsCurrentTop);
  914. Assert.True (ApplicationOverlapped.IsOverlapped(win2));
  915. Assert.Null (top.Focused);
  916. Assert.Null (top.MostFocused);
  917. Assert.Equal (tf1W2, win2.MostFocused);
  918. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  919. ApplicationOverlapped.MoveToOverlappedChild (win1);
  920. Assert.Equal (win1, Application.Current);
  921. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  922. win1.Running = true;
  923. Assert.True (Application.OnKeyDown (Application.QuitKey));
  924. Assert.False (isRunning);
  925. Assert.False (win1.Running);
  926. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  927. // win1 has been closed. It can no longer be focused or acted upon.
  928. // win2 should now have focus
  929. Assert.Equal (win2, Application.Current);
  930. Assert.True (win2.IsCurrentTop);
  931. Assert.Equal (Environment.OSVersion.Platform == PlatformID.Unix, Application.OnKeyDown (Key.Z.WithCtrl)); // suspend
  932. Assert.True (Application.OnKeyDown (Key.F5)); // refresh
  933. Assert.True (win1.IsCurrentTop);
  934. Assert.Equal (tvW1, win1.MostFocused);
  935. Assert.True (Application.OnKeyDown (Key.Tab));
  936. Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  937. Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
  938. Assert.Equal ($"First line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  939. Assert.True (Application.OnKeyDown (Key.F6)); // move to win2
  940. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  941. Assert.True (Application.OnKeyDown (Key.F6.WithShift)); // move back to win1
  942. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  943. Assert.Equal (tvW1, win1.MostFocused);
  944. Assert.True (Application.OnKeyDown (Key.Tab)); // text view eats tab
  945. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  946. Assert.Equal (tvW1, win1.MostFocused);
  947. tvW1.AllowsTab = false;
  948. Assert.True (Application.OnKeyDown (Key.Tab)); // text view eats tab
  949. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  950. Assert.Equal (tf2W1, win1.MostFocused);
  951. Assert.True (Application.OnKeyDown (Key.CursorRight));
  952. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  953. Assert.Equal (tf2W1, win1.MostFocused);
  954. Assert.True (Application.OnKeyDown (Key.CursorDown));
  955. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  956. Assert.Equal (tf1W1, win1.MostFocused);
  957. #if UNIX_KEY_BINDINGS
  958. Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.I.WithCtrl)));
  959. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  960. Assert.Equal (tf2W1, win1.MostFocused);
  961. #endif
  962. Assert.True (Application.OnKeyDown (Key.Tab));
  963. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  964. Assert.Equal (tvW1, win1.MostFocused);
  965. Assert.True (Application.OnKeyDown (Key.CursorLeft)); // The view to the left of tvW1 is tf2W1, but tvW1 is still focused and eats cursor keys
  966. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  967. Assert.Equal (tvW1, win1.MostFocused);
  968. Assert.True (Application.OnKeyDown (Key.CursorUp));
  969. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  970. Assert.Equal (tvW1, win1.MostFocused);
  971. Assert.True (Application.OnKeyDown (Key.Tab));
  972. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  973. Assert.Equal (tf2W1, win1.MostFocused);
  974. Assert.True (Application.OnKeyDown (Key.F6)); // Move to win2
  975. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  976. Assert.Equal (tf1W2, win2.MostFocused);
  977. tf2W2.SetFocus ();
  978. Assert.True (tf2W2.HasFocus);
  979. Assert.True (Application.OnKeyDown (Key.F6.WithShift));
  980. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  981. Assert.Equal (tf2W1, win1.MostFocused);
  982. Assert.True (Application.OnKeyDown (Application.NextTabGroupKey));
  983. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  984. Assert.Equal (tf2W2, win2.MostFocused);
  985. Assert.True (Application.OnKeyDown (Application.PrevTabGroupKey));
  986. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  987. Assert.Equal (tf2W1, win1.MostFocused);
  988. Assert.True (Application.OnKeyDown (Key.CursorDown));
  989. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  990. Assert.Equal (tf1W1, win1.MostFocused);
  991. #if UNIX_KEY_BINDINGS
  992. Assert.True (Application.OnKeyDown (new (Key.B.WithCtrl)));
  993. #else
  994. Assert.True (Application.OnKeyDown (Key.CursorLeft));
  995. #endif
  996. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  997. Assert.Equal (tf1W1, win1.MostFocused);
  998. Assert.True (Application.OnKeyDown (Key.CursorDown));
  999. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  1000. Assert.Equal (tvW1, win1.MostFocused);
  1001. Assert.Equal (Point.Empty, tvW1.CursorPosition);
  1002. Assert.True (Application.OnKeyDown (Key.End.WithCtrl));
  1003. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  1004. Assert.Equal (tvW1, win1.MostFocused);
  1005. Assert.Equal (new (16, 1), tvW1.CursorPosition); // Last position of the text
  1006. #if UNIX_KEY_BINDINGS
  1007. Assert.True (Application.OnKeyDown (new (Key.F.WithCtrl)));
  1008. #else
  1009. Assert.True (Application.OnKeyDown (Key.CursorRight)); // should move to next view w/ in Group (tf2W1)
  1010. #endif
  1011. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  1012. Assert.Equal (tf2W1, win1.MostFocused);
  1013. #if UNIX_KEY_BINDINGS
  1014. Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.L.WithCtrl)));
  1015. #endif
  1016. win2.Dispose ();
  1017. win1.Dispose ();
  1018. top.Dispose ();
  1019. }
  1020. [Fact]
  1021. public void SetFocusToNextViewWithWrap_ShouldFocusNextView ()
  1022. {
  1023. // Arrange
  1024. var superView = new TestToplevel () { Id = "superView", IsOverlappedContainer = true };
  1025. var view1 = new TestView () { Id = "view1" };
  1026. var view2 = new TestView () { Id = "view2" };
  1027. var view3 = new TestView () { Id = "view3" }; ;
  1028. superView.Add (view1, view2, view3);
  1029. var current = new TestToplevel () { Id = "current", IsOverlappedContainer = true };
  1030. superView.Add (current);
  1031. superView.BeginInit ();
  1032. superView.EndInit ();
  1033. current.SetFocus ();
  1034. Application.Current = current;
  1035. Assert.True (current.HasFocus);
  1036. Assert.Equal (superView.Focused, current);
  1037. Assert.Equal (superView.MostFocused, current);
  1038. // Act
  1039. ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView.Subviews, NavigationDirection.Forward);
  1040. // Assert
  1041. Assert.True (view1.HasFocus);
  1042. }
  1043. [Fact]
  1044. public void SetFocusToNextViewWithWrap_ShouldNotChangeFocusIfViewsIsNull ()
  1045. {
  1046. // Arrange
  1047. var currentView = new TestToplevel ();
  1048. Application.Current = currentView;
  1049. // Act
  1050. ApplicationOverlapped.SetFocusToNextViewWithWrap (null, NavigationDirection.Forward);
  1051. // Assert
  1052. Assert.Equal (currentView, Application.Current);
  1053. }
  1054. [Fact]
  1055. public void SetFocusToNextViewWithWrap_ShouldNotChangeFocusIfCurrentViewNotFound ()
  1056. {
  1057. // Arrange
  1058. var view1 = new TestToplevel ();
  1059. var view2 = new TestToplevel ();
  1060. var view3 = new TestToplevel ();
  1061. var views = new List<View> { view1, view2, view3 };
  1062. var currentView = new TestToplevel () { IsOverlappedContainer = true }; // Current view is not in the list
  1063. Application.Current = currentView;
  1064. // Act
  1065. ApplicationOverlapped.SetFocusToNextViewWithWrap (views, NavigationDirection.Forward);
  1066. // Assert
  1067. Assert.False (view1.IsFocused);
  1068. Assert.False (view2.IsFocused);
  1069. Assert.False (view3.IsFocused);
  1070. }
  1071. private class TestToplevel : Toplevel
  1072. {
  1073. public bool IsFocused { get; private set; }
  1074. protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedVew)
  1075. {
  1076. IsFocused = newHasFocus;
  1077. }
  1078. }
  1079. private class TestView : View
  1080. {
  1081. public TestView ()
  1082. {
  1083. CanFocus = true;
  1084. }
  1085. public bool IsFocused { get; private set; }
  1086. protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedVew)
  1087. {
  1088. IsFocused = newHasFocus;
  1089. }
  1090. }
  1091. }