MdiTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Terminal.Gui;
  7. using Xunit;
  8. // Alias Console to MockConsole so we don't accidentally use Console
  9. using Console = Terminal.Gui.FakeConsole;
  10. namespace Terminal.Gui.TopLevelTests {
  11. public class MdiTests {
  12. public MdiTests ()
  13. {
  14. #if DEBUG_IDISPOSABLE
  15. Responder.Instances.Clear ();
  16. Application.RunState.Instances.Clear ();
  17. #endif
  18. }
  19. [Fact]
  20. public void Dispose_Toplevel_IsMdiContainer_False_With_Begin_End ()
  21. {
  22. Application.Init (new FakeDriver ());
  23. var top = new Toplevel ();
  24. var rs = Application.Begin (top);
  25. Application.End (rs);
  26. Application.Shutdown ();
  27. #if DEBUG_IDISPOSABLE
  28. Assert.Equal (2, Responder.Instances.Count);
  29. Assert.True (Responder.Instances [0].WasDisposed);
  30. Assert.True (Responder.Instances [1].WasDisposed);
  31. #endif
  32. }
  33. [Fact]
  34. public void Dispose_Toplevel_IsMdiContainer_True_With_Begin ()
  35. {
  36. Application.Init (new FakeDriver ());
  37. var mdi = new Toplevel { IsMdiContainer = true };
  38. var rs = Application.Begin (mdi);
  39. Application.End (rs);
  40. Application.Shutdown ();
  41. #if DEBUG_IDISPOSABLE
  42. Assert.Equal (2, Responder.Instances.Count);
  43. Assert.True (Responder.Instances [0].WasDisposed);
  44. Assert.True (Responder.Instances [1].WasDisposed);
  45. #endif
  46. }
  47. [Fact, AutoInitShutdown]
  48. public void Application_RequestStop_With_Params_On_A_Not_MdiContainer_Always_Use_Application_Current ()
  49. {
  50. var top1 = new Toplevel ();
  51. var top2 = new Toplevel ();
  52. var top3 = new Window ();
  53. var top4 = new Window ();
  54. var d = new Dialog ();
  55. // top1, top2, top3, d1 = 4
  56. var iterations = 4;
  57. top1.Ready += () => {
  58. Assert.Null (Application.MdiChildes);
  59. Application.Run (top2);
  60. };
  61. top2.Ready += () => {
  62. Assert.Null (Application.MdiChildes);
  63. Application.Run (top3);
  64. };
  65. top3.Ready += () => {
  66. Assert.Null (Application.MdiChildes);
  67. Application.Run (top4);
  68. };
  69. top4.Ready += () => {
  70. Assert.Null (Application.MdiChildes);
  71. Application.Run (d);
  72. };
  73. d.Ready += () => {
  74. Assert.Null (Application.MdiChildes);
  75. // This will close the d because on a not MdiContainer the Application.Current it always used.
  76. Application.RequestStop (top1);
  77. Assert.True (Application.Current == d);
  78. };
  79. d.Closed += (e) => Application.RequestStop (top1);
  80. Application.Iteration += () => {
  81. Assert.Null (Application.MdiChildes);
  82. if (iterations == 4) Assert.True (Application.Current == d);
  83. else if (iterations == 3) Assert.True (Application.Current == top4);
  84. else if (iterations == 2) Assert.True (Application.Current == top3);
  85. else if (iterations == 1) Assert.True (Application.Current == top2);
  86. else Assert.True (Application.Current == top1);
  87. Application.RequestStop (top1);
  88. iterations--;
  89. };
  90. Application.Run (top1);
  91. Assert.Null (Application.MdiChildes);
  92. }
  93. class Mdi : Toplevel {
  94. public Mdi ()
  95. {
  96. IsMdiContainer = true;
  97. }
  98. }
  99. [Fact]
  100. [AutoInitShutdown]
  101. public void MdiContainer_With_Toplevel_RequestStop_Balanced ()
  102. {
  103. var mdi = new Mdi ();
  104. var c1 = new Toplevel ();
  105. var c2 = new Window ();
  106. var c3 = new Window ();
  107. var d = new Dialog ();
  108. // MdiChild = c1, c2, c3
  109. // d1 = 1
  110. var iterations = 4;
  111. mdi.Ready += () => {
  112. Assert.Empty (Application.MdiChildes);
  113. Application.Run (c1);
  114. };
  115. c1.Ready += () => {
  116. Assert.Single (Application.MdiChildes);
  117. Application.Run (c2);
  118. };
  119. c2.Ready += () => {
  120. Assert.Equal (2, Application.MdiChildes.Count);
  121. Application.Run (c3);
  122. };
  123. c3.Ready += () => {
  124. Assert.Equal (3, Application.MdiChildes.Count);
  125. Application.Run (d);
  126. };
  127. // More easy because the Mdi Container handles all at once
  128. d.Ready += () => {
  129. Assert.Equal (3, Application.MdiChildes.Count);
  130. // This will not close the MdiContainer because d is a modal toplevel and will be closed.
  131. mdi.RequestStop ();
  132. };
  133. // Now this will close the MdiContainer propagating through the MdiChildes.
  134. d.Closed += (e) => {
  135. mdi.RequestStop ();
  136. };
  137. Application.Iteration += () => {
  138. if (iterations == 4) {
  139. // The Dialog was not closed before and will be closed now.
  140. Assert.True (Application.Current == d);
  141. Assert.False (d.Running);
  142. } else {
  143. Assert.Equal (iterations, Application.MdiChildes.Count);
  144. for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  145. }
  146. iterations--;
  147. };
  148. Application.Run (mdi);
  149. Assert.Empty (Application.MdiChildes);
  150. }
  151. [Fact]
  152. [AutoInitShutdown]
  153. public void MdiContainer_With_Application_RequestStop_MdiTop_With_Params ()
  154. {
  155. var mdi = new Mdi ();
  156. var c1 = new Toplevel ();
  157. var c2 = new Window ();
  158. var c3 = new Window ();
  159. var d = new Dialog ();
  160. // MdiChild = c1, c2, c3
  161. // d1 = 1
  162. var iterations = 4;
  163. mdi.Ready += () => {
  164. Assert.Empty (Application.MdiChildes);
  165. Application.Run (c1);
  166. };
  167. c1.Ready += () => {
  168. Assert.Single (Application.MdiChildes);
  169. Application.Run (c2);
  170. };
  171. c2.Ready += () => {
  172. Assert.Equal (2, Application.MdiChildes.Count);
  173. Application.Run (c3);
  174. };
  175. c3.Ready += () => {
  176. Assert.Equal (3, Application.MdiChildes.Count);
  177. Application.Run (d);
  178. };
  179. // Also easy because the Mdi Container handles all at once
  180. d.Ready += () => {
  181. Assert.Equal (3, Application.MdiChildes.Count);
  182. // This will not close the MdiContainer because d is a modal toplevel
  183. Application.RequestStop (mdi);
  184. };
  185. // Now this will close the MdiContainer propagating through the MdiChildes.
  186. d.Closed += (e) => Application.RequestStop (mdi);
  187. Application.Iteration += () => {
  188. if (iterations == 4) {
  189. // The Dialog was not closed before and will be closed now.
  190. Assert.True (Application.Current == d);
  191. Assert.False (d.Running);
  192. } else {
  193. Assert.Equal (iterations, Application.MdiChildes.Count);
  194. for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  195. }
  196. iterations--;
  197. };
  198. Application.Run (mdi);
  199. Assert.Empty (Application.MdiChildes);
  200. }
  201. [Fact]
  202. [AutoInitShutdown]
  203. public void MdiContainer_With_Application_RequestStop_MdiTop_Without_Params ()
  204. {
  205. var mdi = new Mdi ();
  206. var c1 = new Toplevel ();
  207. var c2 = new Window ();
  208. var c3 = new Window ();
  209. var d = new Dialog ();
  210. // MdiChild = c1, c2, c3 = 3
  211. // d1 = 1
  212. var iterations = 4;
  213. mdi.Ready += () => {
  214. Assert.Empty (Application.MdiChildes);
  215. Application.Run (c1);
  216. };
  217. c1.Ready += () => {
  218. Assert.Single (Application.MdiChildes);
  219. Application.Run (c2);
  220. };
  221. c2.Ready += () => {
  222. Assert.Equal (2, Application.MdiChildes.Count);
  223. Application.Run (c3);
  224. };
  225. c3.Ready += () => {
  226. Assert.Equal (3, Application.MdiChildes.Count);
  227. Application.Run (d);
  228. };
  229. //More harder because it's sequential.
  230. d.Ready += () => {
  231. Assert.Equal (3, Application.MdiChildes.Count);
  232. // Close the Dialog
  233. Application.RequestStop ();
  234. };
  235. // Now this will close the MdiContainer propagating through the MdiChildes.
  236. d.Closed += (e) => Application.RequestStop (mdi);
  237. Application.Iteration += () => {
  238. if (iterations == 4) {
  239. // The Dialog still is the current top and we can't request stop to MdiContainer
  240. // because we are not using parameter calls.
  241. Assert.True (Application.Current == d);
  242. Assert.False (d.Running);
  243. } else {
  244. Assert.Equal (iterations, Application.MdiChildes.Count);
  245. for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  246. }
  247. iterations--;
  248. };
  249. Application.Run (mdi);
  250. Assert.Empty (Application.MdiChildes);
  251. }
  252. [Fact]
  253. [AutoInitShutdown]
  254. public void IsMdiChild_Testing ()
  255. {
  256. var mdi = new Mdi ();
  257. var c1 = new Toplevel ();
  258. var c2 = new Window ();
  259. var c3 = new Window ();
  260. var d = new Dialog ();
  261. Application.Iteration += () => {
  262. Assert.False (mdi.IsMdiChild);
  263. Assert.True (c1.IsMdiChild);
  264. Assert.True (c2.IsMdiChild);
  265. Assert.True (c3.IsMdiChild);
  266. Assert.False (d.IsMdiChild);
  267. mdi.RequestStop ();
  268. };
  269. Application.Run (mdi);
  270. }
  271. [Fact]
  272. [AutoInitShutdown]
  273. public void Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  274. {
  275. var mdi = new Mdi ();
  276. var c1 = new Toplevel ();
  277. var c2 = new Window ();
  278. var c3 = new Window ();
  279. var d1 = new Dialog ();
  280. var d2 = new Dialog ();
  281. // MdiChild = c1, c2, c3 = 3
  282. // d1, d2 = 2
  283. var iterations = 5;
  284. mdi.Ready += () => {
  285. Assert.Empty (Application.MdiChildes);
  286. Application.Run (c1);
  287. };
  288. c1.Ready += () => {
  289. Assert.Single (Application.MdiChildes);
  290. Application.Run (c2);
  291. };
  292. c2.Ready += () => {
  293. Assert.Equal (2, Application.MdiChildes.Count);
  294. Application.Run (c3);
  295. };
  296. c3.Ready += () => {
  297. Assert.Equal (3, Application.MdiChildes.Count);
  298. Application.Run (d1);
  299. };
  300. d1.Ready += () => {
  301. Assert.Equal (3, Application.MdiChildes.Count);
  302. Application.Run (d2);
  303. };
  304. d2.Ready += () => {
  305. Assert.Equal (3, Application.MdiChildes.Count);
  306. Assert.True (Application.Current == d2);
  307. Assert.True (Application.Current.Running);
  308. // Trying to close the Dialog1
  309. d1.RequestStop ();
  310. };
  311. // Now this will close the MdiContainer propagating through the MdiChildes.
  312. d1.Closed += (e) => {
  313. Assert.True (Application.Current == d1);
  314. Assert.False (Application.Current.Running);
  315. mdi.RequestStop ();
  316. };
  317. Application.Iteration += () => {
  318. if (iterations == 5) {
  319. // The Dialog2 still is the current top and we can't request stop to MdiContainer
  320. // because Dialog2 and Dialog1 must be closed first.
  321. // Dialog2 will be closed in this iteration.
  322. Assert.True (Application.Current == d2);
  323. Assert.False (Application.Current.Running);
  324. Assert.False (d1.Running);
  325. } else if (iterations == 4) {
  326. // Dialog1 will be closed in this iteration.
  327. Assert.True (Application.Current == d1);
  328. Assert.False (Application.Current.Running);
  329. } else {
  330. Assert.Equal (iterations, Application.MdiChildes.Count);
  331. for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.MdiChildes [i].Id);
  332. }
  333. iterations--;
  334. };
  335. Application.Run (mdi);
  336. Assert.Empty (Application.MdiChildes);
  337. }
  338. [Fact]
  339. [AutoInitShutdown]
  340. public void Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  341. {
  342. var mdi = new Mdi ();
  343. var c1 = new Toplevel ();
  344. var c2 = new Window ();
  345. var c3 = new Window ();
  346. var d1 = new Dialog ();
  347. var c4 = new Toplevel ();
  348. // MdiChild = c1, c2, c3, c4 = 4
  349. // d1 = 1
  350. var iterations = 5;
  351. mdi.Ready += () => {
  352. Assert.Empty (Application.MdiChildes);
  353. Application.Run (c1);
  354. };
  355. c1.Ready += () => {
  356. Assert.Single (Application.MdiChildes);
  357. Application.Run (c2);
  358. };
  359. c2.Ready += () => {
  360. Assert.Equal (2, Application.MdiChildes.Count);
  361. Application.Run (c3);
  362. };
  363. c3.Ready += () => {
  364. Assert.Equal (3, Application.MdiChildes.Count);
  365. Application.Run (d1);
  366. };
  367. d1.Ready += () => {
  368. Assert.Equal (3, Application.MdiChildes.Count);
  369. Application.Run (c4);
  370. };
  371. c4.Ready += () => {
  372. Assert.Equal (4, Application.MdiChildes.Count);
  373. // Trying to close the Dialog1
  374. d1.RequestStop ();
  375. };
  376. // Now this will close the MdiContainer propagating through the MdiChildes.
  377. d1.Closed += (e) => {
  378. mdi.RequestStop ();
  379. };
  380. Application.Iteration += () => {
  381. if (iterations == 5) {
  382. // The Dialog2 still is the current top and we can't request stop to MdiContainer
  383. // because Dialog2 and Dialog1 must be closed first.
  384. // Using request stop here will call the Dialog again without need
  385. Assert.True (Application.Current == d1);
  386. Assert.False (Application.Current.Running);
  387. Assert.True (c4.Running);
  388. } else {
  389. Assert.Equal (iterations, Application.MdiChildes.Count);
  390. for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
  391. Application.MdiChildes [i].Id);
  392. }
  393. iterations--;
  394. };
  395. Application.Run (mdi);
  396. Assert.Empty (Application.MdiChildes);
  397. }
  398. [Fact]
  399. [AutoInitShutdown]
  400. public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
  401. {
  402. var mdi = new Mdi ();
  403. var c1 = new Toplevel ();
  404. var c2 = new Window ();
  405. var c3 = new Window ();
  406. // MdiChild = c1, c2, c3
  407. var iterations = 3;
  408. mdi.Ready += () => {
  409. Assert.Empty (Application.MdiChildes);
  410. Application.Run (c1);
  411. };
  412. c1.Ready += () => {
  413. Assert.Single (Application.MdiChildes);
  414. Application.Run (c2);
  415. };
  416. c2.Ready += () => {
  417. Assert.Equal (2, Application.MdiChildes.Count);
  418. Application.Run (c3);
  419. };
  420. c3.Ready += () => {
  421. Assert.Equal (3, Application.MdiChildes.Count);
  422. c3.RequestStop ();
  423. c1.RequestStop ();
  424. };
  425. // Now this will close the MdiContainer propagating through the MdiChildes.
  426. c1.Closed += (e) => {
  427. mdi.RequestStop ();
  428. };
  429. Application.Iteration += () => {
  430. if (iterations == 3) {
  431. // The Current still is c3 because Current.Running is false.
  432. Assert.True (Application.Current == c3);
  433. Assert.False (Application.Current.Running);
  434. // But the childes order were reorder by Running = false
  435. Assert.True (Application.MdiChildes [0] == c3);
  436. Assert.True (Application.MdiChildes [1] == c1);
  437. Assert.True (Application.MdiChildes [^1] == c2);
  438. } else if (iterations == 2) {
  439. // The Current is c1 and Current.Running is false.
  440. Assert.True (Application.Current == c1);
  441. Assert.False (Application.Current.Running);
  442. Assert.True (Application.MdiChildes [0] == c1);
  443. Assert.True (Application.MdiChildes [^1] == c2);
  444. } else if (iterations == 1) {
  445. // The Current is c2 and Current.Running is false.
  446. Assert.True (Application.Current == c2);
  447. Assert.False (Application.Current.Running);
  448. Assert.True (Application.MdiChildes [^1] == c2);
  449. } else {
  450. // The Current is mdi.
  451. Assert.True (Application.Current == mdi);
  452. Assert.Empty (Application.MdiChildes);
  453. }
  454. iterations--;
  455. };
  456. Application.Run (mdi);
  457. Assert.Empty (Application.MdiChildes);
  458. }
  459. [Fact]
  460. [AutoInitShutdown]
  461. public void MdiContainer_Throws_If_More_Than_One ()
  462. {
  463. var mdi = new Mdi ();
  464. var mdi2 = new Mdi ();
  465. mdi.Ready += () => {
  466. Assert.Throws<InvalidOperationException> (() => Application.Run (mdi2));
  467. mdi.RequestStop ();
  468. };
  469. Application.Run (mdi);
  470. }
  471. [Fact]
  472. [AutoInitShutdown]
  473. public void MdiContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
  474. {
  475. var mdi = new Mdi ();
  476. var logger = new Toplevel ();
  477. var iterations = 1; // The logger
  478. var running = true;
  479. var stageCompleted = true;
  480. var allStageClosed = false;
  481. var mdiRequestStop = false;
  482. mdi.Ready += () => {
  483. Assert.Empty (Application.MdiChildes);
  484. Application.Run (logger);
  485. };
  486. logger.Ready += () => Assert.Single (Application.MdiChildes);
  487. Application.Iteration += () => {
  488. if (stageCompleted && running) {
  489. stageCompleted = false;
  490. var stage = new Window () { Modal = true };
  491. stage.Ready += () => {
  492. Assert.Equal (iterations, Application.MdiChildes.Count);
  493. stage.RequestStop ();
  494. };
  495. stage.Closed += (_) => {
  496. if (iterations == 11) allStageClosed = true;
  497. Assert.Equal (iterations, Application.MdiChildes.Count);
  498. if (running) {
  499. stageCompleted = true;
  500. var rpt = new Window ();
  501. rpt.Ready += () => {
  502. iterations++;
  503. Assert.Equal (iterations, Application.MdiChildes.Count);
  504. };
  505. Application.Run (rpt);
  506. }
  507. };
  508. Application.Run (stage);
  509. } else if (iterations == 11 && running) {
  510. running = false;
  511. Assert.Equal (iterations, Application.MdiChildes.Count);
  512. } else if (!mdiRequestStop && running && !allStageClosed) Assert.Equal (iterations, Application.MdiChildes.Count);
  513. else if (!mdiRequestStop && !running && allStageClosed) {
  514. Assert.Equal (iterations, Application.MdiChildes.Count);
  515. mdiRequestStop = true;
  516. mdi.RequestStop ();
  517. } else Assert.Empty (Application.MdiChildes);
  518. };
  519. Application.Run (mdi);
  520. Assert.Empty (Application.MdiChildes);
  521. }
  522. [Fact]
  523. [AutoInitShutdown]
  524. public void AllChildClosed_Event_Test ()
  525. {
  526. var mdi = new Mdi ();
  527. var c1 = new Toplevel ();
  528. var c2 = new Window ();
  529. var c3 = new Window ();
  530. // MdiChild = c1, c2, c3
  531. var iterations = 3;
  532. mdi.Ready += () => {
  533. Assert.Empty (Application.MdiChildes);
  534. Application.Run (c1);
  535. };
  536. c1.Ready += () => {
  537. Assert.Single (Application.MdiChildes);
  538. Application.Run (c2);
  539. };
  540. c2.Ready += () => {
  541. Assert.Equal (2, Application.MdiChildes.Count);
  542. Application.Run (c3);
  543. };
  544. c3.Ready += () => {
  545. Assert.Equal (3, Application.MdiChildes.Count);
  546. c3.RequestStop ();
  547. c2.RequestStop ();
  548. c1.RequestStop ();
  549. };
  550. // Now this will close the MdiContainer when all MdiChildes was closed
  551. mdi.AllChildClosed += () => {
  552. mdi.RequestStop ();
  553. };
  554. Application.Iteration += () => {
  555. if (iterations == 3) {
  556. // The Current still is c3 because Current.Running is false.
  557. Assert.True (Application.Current == c3);
  558. Assert.False (Application.Current.Running);
  559. // But the childes order were reorder by Running = false
  560. Assert.True (Application.MdiChildes [0] == c3);
  561. Assert.True (Application.MdiChildes [1] == c2);
  562. Assert.True (Application.MdiChildes [^1] == c1);
  563. } else if (iterations == 2) {
  564. // The Current is c2 and Current.Running is false.
  565. Assert.True (Application.Current == c2);
  566. Assert.False (Application.Current.Running);
  567. Assert.True (Application.MdiChildes [0] == c2);
  568. Assert.True (Application.MdiChildes [^1] == c1);
  569. } else if (iterations == 1) {
  570. // The Current is c1 and Current.Running is false.
  571. Assert.True (Application.Current == c1);
  572. Assert.False (Application.Current.Running);
  573. Assert.True (Application.MdiChildes [^1] == c1);
  574. } else {
  575. // The Current is mdi.
  576. Assert.True (Application.Current == mdi);
  577. Assert.False (Application.Current.Running);
  578. Assert.Empty (Application.MdiChildes);
  579. }
  580. iterations--;
  581. };
  582. Application.Run (mdi);
  583. Assert.Empty (Application.MdiChildes);
  584. }
  585. }
  586. }