SubviewTests.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. namespace Terminal.Gui.ViewTests;
  2. [Collection ("Global Test Setup")]
  3. public class SubViewTests
  4. {
  5. [Fact]
  6. public void SuperViewChanged_Raised_On_Add ()
  7. {
  8. var super = new View { };
  9. var sub = new View ();
  10. int superRaisedCount = 0;
  11. int subRaisedCount = 0;
  12. super.SuperViewChanged += (s, e) =>
  13. {
  14. superRaisedCount++;
  15. };
  16. sub.SuperViewChanged += (s, e) =>
  17. {
  18. if (e.SuperView is {})
  19. {
  20. subRaisedCount++;
  21. }
  22. };
  23. super.Add (sub);
  24. Assert.True (super.SubViews.Count == 1);
  25. Assert.Equal (super, sub.SuperView);
  26. Assert.Equal (0, superRaisedCount);
  27. Assert.Equal (1, subRaisedCount);
  28. }
  29. [Fact]
  30. public void SuperViewChanged_Raised_On_Remove ()
  31. {
  32. var super = new View { };
  33. var sub = new View ();
  34. int superRaisedCount = 0;
  35. int subRaisedCount = 0;
  36. super.SuperViewChanged += (s, e) =>
  37. {
  38. superRaisedCount++;
  39. };
  40. sub.SuperViewChanged += (s, e) =>
  41. {
  42. if (e.SuperView is null)
  43. {
  44. subRaisedCount++;
  45. }
  46. };
  47. super.Add (sub);
  48. Assert.True (super.SubViews.Count == 1);
  49. Assert.Equal (super, sub.SuperView);
  50. Assert.Equal (0, superRaisedCount);
  51. Assert.Equal (0, subRaisedCount);
  52. super.Remove (sub);
  53. Assert.Empty (super.SubViews);
  54. Assert.NotEqual (super, sub.SuperView);
  55. Assert.Equal (0, superRaisedCount);
  56. Assert.Equal (1, subRaisedCount);
  57. }
  58. [Fact]
  59. public void SuperView_Set_On_Add_Remove ()
  60. {
  61. var superView = new View ();
  62. var view = new View ();
  63. Assert.Null (view.SuperView);
  64. superView.Add (view);
  65. Assert.Equal (superView, view.SuperView);
  66. superView.Remove (view);
  67. Assert.Null (view.SuperView);
  68. }
  69. // TODO: Consider a feature that will change the ContentSize to fit the subviews.
  70. [Fact]
  71. public void Add_Does_Not_Impact_ContentSize ()
  72. {
  73. var view = new View ();
  74. view.SetContentSize (new Size (1, 1));
  75. var subview = new View
  76. {
  77. X = 10,
  78. Y = 10
  79. };
  80. Assert.Equal (new (1, 1), view.GetContentSize ());
  81. view.Add (subview);
  82. Assert.Equal (new (1, 1), view.GetContentSize ());
  83. }
  84. [Fact]
  85. public void Remove_Does_Not_Impact_ContentSize ()
  86. {
  87. var view = new View ();
  88. view.SetContentSize (new Size (1, 1));
  89. var subview = new View
  90. {
  91. X = 10,
  92. Y = 10
  93. };
  94. Assert.Equal (new (1, 1), view.GetContentSize ());
  95. view.Add (subview);
  96. Assert.Equal (new (1, 1), view.GetContentSize ());
  97. view.SetContentSize (new Size (5, 5));
  98. Assert.Equal (new (5, 5), view.GetContentSize ());
  99. view.Remove (subview);
  100. Assert.Equal (new (5, 5), view.GetContentSize ());
  101. }
  102. [Fact]
  103. public void MoveSubViewToStart ()
  104. {
  105. View superView = new ();
  106. var subview1 = new View
  107. {
  108. Id = "subview1"
  109. };
  110. var subview2 = new View
  111. {
  112. Id = "subview2"
  113. };
  114. var subview3 = new View
  115. {
  116. Id = "subview3"
  117. };
  118. superView.Add (subview1, subview2, subview3);
  119. superView.MoveSubViewToStart (subview2);
  120. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  121. superView.MoveSubViewToStart (subview3);
  122. Assert.Equal (subview3, superView.SubViews.ElementAt (0));
  123. }
  124. [Fact]
  125. public void MoveSubViewTowardsFront ()
  126. {
  127. View superView = new ();
  128. var subview1 = new View
  129. {
  130. Id = "subview1"
  131. };
  132. var subview2 = new View
  133. {
  134. Id = "subview2"
  135. };
  136. var subview3 = new View
  137. {
  138. Id = "subview3"
  139. };
  140. superView.Add (subview1, subview2, subview3);
  141. superView.MoveSubViewTowardsStart (subview2);
  142. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  143. superView.MoveSubViewTowardsStart (subview3);
  144. Assert.Equal (subview3, superView.SubViews.ElementAt (1));
  145. // Already at front, what happens?
  146. superView.MoveSubViewTowardsStart (subview2);
  147. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  148. }
  149. [Fact]
  150. public void MoveSubViewToEnd ()
  151. {
  152. View superView = new ();
  153. var subview1 = new View
  154. {
  155. Id = "subview1"
  156. };
  157. var subview2 = new View
  158. {
  159. Id = "subview2"
  160. };
  161. var subview3 = new View
  162. {
  163. Id = "subview3"
  164. };
  165. superView.Add (subview1, subview2, subview3);
  166. superView.MoveSubViewToEnd (subview1);
  167. Assert.Equal (subview1, superView.SubViews.ToArray () [^1]);
  168. superView.MoveSubViewToEnd (subview2);
  169. Assert.Equal (subview2, superView.SubViews.ToArray () [^1]);
  170. }
  171. [Fact]
  172. public void MoveSubViewTowardsEnd ()
  173. {
  174. View superView = new ();
  175. var subview1 = new View
  176. {
  177. Id = "subview1"
  178. };
  179. var subview2 = new View
  180. {
  181. Id = "subview2"
  182. };
  183. var subview3 = new View
  184. {
  185. Id = "subview3"
  186. };
  187. superView.Add (subview1, subview2, subview3);
  188. superView.MoveSubViewTowardsEnd (subview2);
  189. Assert.Equal (subview2, superView.SubViews.ToArray() [^1]);
  190. superView.MoveSubViewTowardsEnd (subview1);
  191. Assert.Equal (subview1, superView.SubViews.ToArray() [1]);
  192. // Already at end, what happens?
  193. superView.MoveSubViewTowardsEnd (subview2);
  194. Assert.Equal (subview2, superView.SubViews.ToArray() [^1]);
  195. }
  196. [Fact]
  197. public void IsInHierarchy_ViewIsNull_ReturnsFalse ()
  198. {
  199. // Arrange
  200. var start = new View ();
  201. // Act
  202. bool result = View.IsInHierarchy (start, null);
  203. // Assert
  204. Assert.False (result);
  205. }
  206. [Fact]
  207. public void IsInHierarchy_StartIsNull_ReturnsFalse ()
  208. {
  209. // Arrange
  210. var view = new View ();
  211. // Act
  212. bool result = View.IsInHierarchy (null, view);
  213. // Assert
  214. Assert.False (result);
  215. }
  216. [Fact]
  217. public void IsInHierarchy_ViewIsStart_ReturnsTrue ()
  218. {
  219. // Arrange
  220. var start = new View ();
  221. // Act
  222. bool result = View.IsInHierarchy (start, start);
  223. // Assert
  224. Assert.True (result);
  225. }
  226. [Fact]
  227. public void IsInHierarchy_ViewIsDirectSubView_ReturnsTrue ()
  228. {
  229. // Arrange
  230. var start = new View ();
  231. var subview = new View ();
  232. start.Add (subview);
  233. // Act
  234. bool result = View.IsInHierarchy (start, subview);
  235. // Assert
  236. Assert.True (result);
  237. }
  238. [Fact]
  239. public void IsInHierarchy_ViewIsNestedSubView_ReturnsTrue ()
  240. {
  241. // Arrange
  242. var start = new View ();
  243. var subview = new View ();
  244. var nestedSubView = new View ();
  245. start.Add (subview);
  246. subview.Add (nestedSubView);
  247. // Act
  248. bool result = View.IsInHierarchy (start, nestedSubView);
  249. // Assert
  250. Assert.True (result);
  251. }
  252. [Fact]
  253. public void IsInHierarchy_ViewIsNotInHierarchy_ReturnsFalse ()
  254. {
  255. // Arrange
  256. var start = new View ();
  257. var subview = new View ();
  258. // Act
  259. bool result = View.IsInHierarchy (start, subview);
  260. // Assert
  261. Assert.False (result);
  262. }
  263. [Theory]
  264. [CombinatorialData]
  265. public void IsInHierarchy_ViewIsInAdornments_ReturnsTrue (bool includeAdornments)
  266. {
  267. // Arrange
  268. var start = new View
  269. {
  270. Id = "start"
  271. };
  272. var inPadding = new View
  273. {
  274. Id = "inPadding"
  275. };
  276. start.Padding!.Add (inPadding);
  277. // Act
  278. bool result = View.IsInHierarchy (start, inPadding, includeAdornments);
  279. // Assert
  280. Assert.Equal (includeAdornments, result);
  281. }
  282. [Fact]
  283. public void SuperView_Set_Raises_SuperViewChangedEvents ()
  284. {
  285. // Arrange
  286. var view = new View ();
  287. var superView = new View ();
  288. int superViewChangedCount = 0;
  289. //int superViewChangingCount = 0;
  290. view.SuperViewChanged += (s, e) =>
  291. {
  292. superViewChangedCount++;
  293. };
  294. //view.SuperViewChanging += (s, e) =>
  295. //{
  296. // superViewChangingCount++;
  297. //};
  298. // Act
  299. superView.Add (view);
  300. // Assert
  301. //Assert.Equal (1, superViewChangingCount);
  302. Assert.Equal (1, superViewChangedCount);
  303. }
  304. [Fact]
  305. public void GetTopSuperView_Test ()
  306. {
  307. var v1 = new View ();
  308. var fv1 = new FrameView ();
  309. fv1.Add (v1);
  310. var tf1 = new TextField ();
  311. var w1 = new Window ();
  312. w1.Add (fv1, tf1);
  313. var top1 = new Toplevel ();
  314. top1.Add (w1);
  315. var v2 = new View ();
  316. var fv2 = new FrameView ();
  317. fv2.Add (v2);
  318. var tf2 = new TextField ();
  319. var w2 = new Window ();
  320. w2.Add (fv2, tf2);
  321. var top2 = new Toplevel ();
  322. top2.Add (w2);
  323. Assert.Equal (top1, v1.GetTopSuperView ());
  324. Assert.Equal (top2, v2.GetTopSuperView ());
  325. v1.Dispose ();
  326. fv1.Dispose ();
  327. tf1.Dispose ();
  328. w1.Dispose ();
  329. top1.Dispose ();
  330. v2.Dispose ();
  331. fv2.Dispose ();
  332. tf2.Dispose ();
  333. w2.Dispose ();
  334. top2.Dispose ();
  335. }
  336. [Fact]
  337. public void Initialized_Event_Comparing_With_Added_Event ()
  338. {
  339. var top = new Toplevel { Id = "0" }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 80, 25
  340. var winAddedToTop = new Window
  341. {
  342. Id = "t", Width = Dim.Fill (), Height = Dim.Fill ()
  343. }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 78, 23
  344. var v1AddedToWin = new View
  345. {
  346. Id = "v1", Width = Dim.Fill (), Height = Dim.Fill ()
  347. }; // Frame: 1, 1, 78, 23 (because Windows has a border)
  348. var v2AddedToWin = new View
  349. {
  350. Id = "v2", Width = Dim.Fill (), Height = Dim.Fill ()
  351. }; // Frame: 1, 1, 78, 23 (because Windows has a border)
  352. var svAddedTov1 = new View
  353. {
  354. Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill ()
  355. }; // Frame: 1, 1, 78, 23 (same as it's superview v1AddedToWin)
  356. int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
  357. winAddedToTop.SubViewAdded += (s, e) =>
  358. {
  359. Assert.Equal (e.SuperView.Frame.Width, winAddedToTop.Frame.Width);
  360. Assert.Equal (e.SuperView.Frame.Height, winAddedToTop.Frame.Height);
  361. };
  362. v1AddedToWin.SubViewAdded += (s, e) =>
  363. {
  364. Assert.Equal (e.SuperView.Frame.Width, v1AddedToWin.Frame.Width);
  365. Assert.Equal (e.SuperView.Frame.Height, v1AddedToWin.Frame.Height);
  366. };
  367. v2AddedToWin.SubViewAdded += (s, e) =>
  368. {
  369. Assert.Equal (e.SuperView.Frame.Width, v2AddedToWin.Frame.Width);
  370. Assert.Equal (e.SuperView.Frame.Height, v2AddedToWin.Frame.Height);
  371. };
  372. svAddedTov1.SubViewAdded += (s, e) =>
  373. {
  374. Assert.Equal (e.SuperView.Frame.Width, svAddedTov1.Frame.Width);
  375. Assert.Equal (e.SuperView.Frame.Height, svAddedTov1.Frame.Height);
  376. };
  377. top.Initialized += (s, e) =>
  378. {
  379. tc++;
  380. Assert.Equal (1, tc);
  381. Assert.Equal (1, wc);
  382. Assert.Equal (1, v1c);
  383. Assert.Equal (1, v2c);
  384. Assert.Equal (1, sv1c);
  385. Assert.True (top.CanFocus);
  386. Assert.True (winAddedToTop.CanFocus);
  387. Assert.False (v1AddedToWin.CanFocus);
  388. Assert.False (v2AddedToWin.CanFocus);
  389. Assert.False (svAddedTov1.CanFocus);
  390. Application.LayoutAndDraw ();
  391. };
  392. winAddedToTop.Initialized += (s, e) =>
  393. {
  394. wc++;
  395. Assert.Equal (top.Viewport.Width, winAddedToTop.Frame.Width);
  396. Assert.Equal (top.Viewport.Height, winAddedToTop.Frame.Height);
  397. };
  398. v1AddedToWin.Initialized += (s, e) =>
  399. {
  400. v1c++;
  401. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  402. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  403. // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Viewport
  404. // as it is a subview of winAddedToTop, which has a border!
  405. //Assert.Equal (top.Viewport.Width, v1AddedToWin.Frame.Width);
  406. //Assert.Equal (top.Viewport.Height, v1AddedToWin.Frame.Height);
  407. };
  408. v2AddedToWin.Initialized += (s, e) =>
  409. {
  410. v2c++;
  411. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  412. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  413. // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Viewport
  414. // as it is a subview of winAddedToTop, which has a border!
  415. //Assert.Equal (top.Viewport.Width, v2AddedToWin.Frame.Width);
  416. //Assert.Equal (top.Viewport.Height, v2AddedToWin.Frame.Height);
  417. };
  418. svAddedTov1.Initialized += (s, e) =>
  419. {
  420. sv1c++;
  421. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  422. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  423. // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Viewport
  424. // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of
  425. // winAddedToTop, which has a border!
  426. //Assert.Equal (top.Viewport.Width, svAddedTov1.Frame.Width);
  427. //Assert.Equal (top.Viewport.Height, svAddedTov1.Frame.Height);
  428. Assert.False (svAddedTov1.CanFocus);
  429. //Assert.Throws<InvalidOperationException> (() => svAddedTov1.CanFocus = true);
  430. Assert.False (svAddedTov1.CanFocus);
  431. };
  432. v1AddedToWin.Add (svAddedTov1);
  433. winAddedToTop.Add (v1AddedToWin, v2AddedToWin);
  434. top.Add (winAddedToTop);
  435. top.BeginInit ();
  436. top.EndInit ();
  437. Assert.Equal (1, tc);
  438. Assert.Equal (1, wc);
  439. Assert.Equal (1, v1c);
  440. Assert.Equal (1, v2c);
  441. Assert.Equal (1, sv1c);
  442. Assert.True (top.CanFocus);
  443. Assert.True (winAddedToTop.CanFocus);
  444. Assert.False (v1AddedToWin.CanFocus);
  445. Assert.False (v2AddedToWin.CanFocus);
  446. Assert.False (svAddedTov1.CanFocus);
  447. v1AddedToWin.CanFocus = true;
  448. Assert.False (svAddedTov1.CanFocus); // False because sv1 was disposed and it isn't a subview of v1.
  449. }
  450. [Fact]
  451. public void SuperViewChanged_Raised_On_SubViewAdded_SubViewRemoved ()
  452. {
  453. var isAdded = false;
  454. View superView = new () { Id = "superView" };
  455. View subView = new () { Id = "subView" };
  456. superView.SubViewAdded += (s, e) =>
  457. {
  458. Assert.True (isAdded);
  459. Assert.Equal (superView, subView.SuperView);
  460. Assert.Equal (subView, e.SubView);
  461. Assert.Equal (superView, e.SuperView);
  462. };
  463. superView.SubViewRemoved += (s, e) =>
  464. {
  465. Assert.False (isAdded);
  466. Assert.NotEqual (superView, subView.SuperView);
  467. Assert.Equal (subView, e.SubView);
  468. Assert.Equal (superView, e.SuperView);
  469. };
  470. subView.SuperViewChanged += (s, e) => { isAdded = subView.SuperView == superView; };
  471. superView.Add (subView);
  472. Assert.True (isAdded);
  473. Assert.Equal (superView, subView.SuperView);
  474. Assert.Single (superView.SubViews);
  475. superView.Remove (subView);
  476. Assert.False (isAdded);
  477. Assert.NotEqual (superView, subView.SuperView);
  478. Assert.Empty (superView.SubViews);
  479. }
  480. [Fact]
  481. public void RemoveAll_Removes_All_SubViews ()
  482. {
  483. // Arrange
  484. var superView = new View ();
  485. var subView1 = new View ();
  486. var subView2 = new View ();
  487. var subView3 = new View ();
  488. superView.Add (subView1, subView2, subView3);
  489. // Act
  490. var removedViews = superView.RemoveAll ();
  491. // Assert
  492. Assert.Empty (superView.SubViews);
  493. Assert.Equal (3, removedViews.Count);
  494. Assert.Contains (subView1, removedViews);
  495. Assert.Contains (subView2, removedViews);
  496. Assert.Contains (subView3, removedViews);
  497. }
  498. [Fact]
  499. public void RemoveAllTView_Removes_All_SubViews_Of_Specific_Type ()
  500. {
  501. // Arrange
  502. var superView = new View ();
  503. var subView1 = new View ();
  504. var subView2 = new View ();
  505. var subView3 = new View ();
  506. var subView4 = new Button ();
  507. superView.Add (subView1, subView2, subView3, subView4);
  508. // Act
  509. var removedViews = superView.RemoveAll<Button> ();
  510. // Assert
  511. Assert.Equal (3, superView.SubViews.Count);
  512. Assert.DoesNotContain (subView4, superView.SubViews);
  513. Assert.Single (removedViews);
  514. Assert.Contains (subView4, removedViews);
  515. }
  516. [Fact]
  517. public void RemoveAllTView_Does_Not_Remove_Other_Types ()
  518. {
  519. // Arrange
  520. var superView = new View ();
  521. var subView1 = new View ();
  522. var subView2 = new Button ();
  523. var subView3 = new Label ();
  524. superView.Add (subView1, subView2, subView3);
  525. // Act
  526. var removedViews = superView.RemoveAll<Button> ();
  527. // Assert
  528. Assert.Equal (2, superView.SubViews.Count);
  529. Assert.Contains (subView1, superView.SubViews);
  530. Assert.Contains (subView3, superView.SubViews);
  531. Assert.Single (removedViews);
  532. Assert.Contains (subView2, removedViews);
  533. }
  534. }