SubviewTests.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. namespace UnitTests_Parallelizable.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. [Theory]
  103. [InlineData (ViewArrangement.Fixed)]
  104. [InlineData (ViewArrangement.Overlapped)]
  105. public void MoveSubViewToEnd_ViewArrangement (ViewArrangement arrangement)
  106. {
  107. View superView = new () { Arrangement = arrangement };
  108. var subview1 = new View
  109. {
  110. Id = "subview1"
  111. };
  112. var subview2 = new View
  113. {
  114. Id = "subview2"
  115. };
  116. var subview3 = new View
  117. {
  118. Id = "subview3"
  119. };
  120. superView.Add (subview1, subview2, subview3);
  121. superView.MoveSubViewToEnd (subview1);
  122. Assert.Equal ([subview2, subview3, subview1], superView.SubViews.ToArray ());
  123. superView.MoveSubViewToEnd (subview2);
  124. Assert.Equal ([subview3, subview1, subview2], superView.SubViews.ToArray ());
  125. superView.MoveSubViewToEnd (subview3);
  126. Assert.Equal ([subview1, subview2, subview3], superView.SubViews.ToArray ());
  127. }
  128. [Fact]
  129. public void MoveSubViewToStart ()
  130. {
  131. View superView = new ();
  132. var subview1 = new View
  133. {
  134. Id = "subview1"
  135. };
  136. var subview2 = new View
  137. {
  138. Id = "subview2"
  139. };
  140. var subview3 = new View
  141. {
  142. Id = "subview3"
  143. };
  144. superView.Add (subview1, subview2, subview3);
  145. superView.MoveSubViewToStart (subview2);
  146. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  147. superView.MoveSubViewToStart (subview3);
  148. Assert.Equal (subview3, superView.SubViews.ElementAt (0));
  149. }
  150. [Fact]
  151. public void MoveSubViewTowardsFront ()
  152. {
  153. View superView = new ();
  154. var subview1 = new View
  155. {
  156. Id = "subview1"
  157. };
  158. var subview2 = new View
  159. {
  160. Id = "subview2"
  161. };
  162. var subview3 = new View
  163. {
  164. Id = "subview3"
  165. };
  166. superView.Add (subview1, subview2, subview3);
  167. superView.MoveSubViewTowardsStart (subview2);
  168. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  169. superView.MoveSubViewTowardsStart (subview3);
  170. Assert.Equal (subview3, superView.SubViews.ElementAt (1));
  171. // Already at front, what happens?
  172. superView.MoveSubViewTowardsStart (subview2);
  173. Assert.Equal (subview2, superView.SubViews.ElementAt (0));
  174. }
  175. [Fact]
  176. public void MoveSubViewToEnd ()
  177. {
  178. View superView = new ();
  179. var subview1 = new View
  180. {
  181. Id = "subview1"
  182. };
  183. var subview2 = new View
  184. {
  185. Id = "subview2"
  186. };
  187. var subview3 = new View
  188. {
  189. Id = "subview3"
  190. };
  191. superView.Add (subview1, subview2, subview3);
  192. superView.MoveSubViewToEnd (subview1);
  193. Assert.Equal (subview1, superView.SubViews.ToArray () [^1]);
  194. superView.MoveSubViewToEnd (subview2);
  195. Assert.Equal (subview2, superView.SubViews.ToArray () [^1]);
  196. }
  197. [Fact]
  198. public void MoveSubViewTowardsEnd ()
  199. {
  200. View superView = new ();
  201. var subview1 = new View
  202. {
  203. Id = "subview1"
  204. };
  205. var subview2 = new View
  206. {
  207. Id = "subview2"
  208. };
  209. var subview3 = new View
  210. {
  211. Id = "subview3"
  212. };
  213. superView.Add (subview1, subview2, subview3);
  214. superView.MoveSubViewTowardsEnd (subview2);
  215. Assert.Equal (subview2, superView.SubViews.ToArray () [^1]);
  216. superView.MoveSubViewTowardsEnd (subview1);
  217. Assert.Equal (subview1, superView.SubViews.ToArray () [1]);
  218. // Already at end, what happens?
  219. superView.MoveSubViewTowardsEnd (subview2);
  220. Assert.Equal (subview2, superView.SubViews.ToArray () [^1]);
  221. }
  222. [Fact]
  223. public void IsInHierarchy_ViewIsNull_ReturnsFalse ()
  224. {
  225. // Arrange
  226. var start = new View ();
  227. // Act
  228. bool result = View.IsInHierarchy (start, null);
  229. // Assert
  230. Assert.False (result);
  231. }
  232. [Fact]
  233. public void IsInHierarchy_StartIsNull_ReturnsFalse ()
  234. {
  235. // Arrange
  236. var view = new View ();
  237. // Act
  238. bool result = View.IsInHierarchy (null, view);
  239. // Assert
  240. Assert.False (result);
  241. }
  242. [Fact]
  243. public void IsInHierarchy_ViewIsStart_ReturnsTrue ()
  244. {
  245. // Arrange
  246. var start = new View ();
  247. // Act
  248. bool result = View.IsInHierarchy (start, start);
  249. // Assert
  250. Assert.True (result);
  251. }
  252. [Fact]
  253. public void IsInHierarchy_ViewIsDirectSubView_ReturnsTrue ()
  254. {
  255. // Arrange
  256. var start = new View ();
  257. var subview = new View ();
  258. start.Add (subview);
  259. // Act
  260. bool result = View.IsInHierarchy (start, subview);
  261. // Assert
  262. Assert.True (result);
  263. }
  264. [Fact]
  265. public void IsInHierarchy_ViewIsNestedSubView_ReturnsTrue ()
  266. {
  267. // Arrange
  268. var start = new View ();
  269. var subview = new View ();
  270. var nestedSubView = new View ();
  271. start.Add (subview);
  272. subview.Add (nestedSubView);
  273. // Act
  274. bool result = View.IsInHierarchy (start, nestedSubView);
  275. // Assert
  276. Assert.True (result);
  277. }
  278. [Fact]
  279. public void IsInHierarchy_ViewIsNotInHierarchy_ReturnsFalse ()
  280. {
  281. // Arrange
  282. var start = new View ();
  283. var subview = new View ();
  284. // Act
  285. bool result = View.IsInHierarchy (start, subview);
  286. // Assert
  287. Assert.False (result);
  288. }
  289. [Theory]
  290. [CombinatorialData]
  291. public void IsInHierarchy_ViewIsInAdornments_ReturnsTrue (bool includeAdornments)
  292. {
  293. // Arrange
  294. var start = new View
  295. {
  296. Id = "start"
  297. };
  298. var inPadding = new View
  299. {
  300. Id = "inPadding"
  301. };
  302. start.Padding!.Add (inPadding);
  303. // Act
  304. bool result = View.IsInHierarchy (start, inPadding, includeAdornments);
  305. // Assert
  306. Assert.Equal (includeAdornments, result);
  307. }
  308. [Fact]
  309. public void SuperView_Set_Raises_SuperViewChangedEvents ()
  310. {
  311. // Arrange
  312. var view = new View ();
  313. var superView = new View ();
  314. int superViewChangedCount = 0;
  315. //int superViewChangingCount = 0;
  316. view.SuperViewChanged += (s, e) =>
  317. {
  318. superViewChangedCount++;
  319. };
  320. //view.SuperViewChanging += (s, e) =>
  321. //{
  322. // superViewChangingCount++;
  323. //};
  324. // Act
  325. superView.Add (view);
  326. // Assert
  327. //Assert.Equal (1, superViewChangingCount);
  328. Assert.Equal (1, superViewChangedCount);
  329. }
  330. [Fact]
  331. public void GetTopSuperView_Test ()
  332. {
  333. var v1 = new View ();
  334. var fv1 = new FrameView ();
  335. fv1.Add (v1);
  336. var tf1 = new TextField ();
  337. var w1 = new Window ();
  338. w1.Add (fv1, tf1);
  339. var top1 = new Toplevel ();
  340. top1.Add (w1);
  341. var v2 = new View ();
  342. var fv2 = new FrameView ();
  343. fv2.Add (v2);
  344. var tf2 = new TextField ();
  345. var w2 = new Window ();
  346. w2.Add (fv2, tf2);
  347. var top2 = new Toplevel ();
  348. top2.Add (w2);
  349. Assert.Equal (top1, v1.GetTopSuperView ());
  350. Assert.Equal (top2, v2.GetTopSuperView ());
  351. v1.Dispose ();
  352. fv1.Dispose ();
  353. tf1.Dispose ();
  354. w1.Dispose ();
  355. top1.Dispose ();
  356. v2.Dispose ();
  357. fv2.Dispose ();
  358. tf2.Dispose ();
  359. w2.Dispose ();
  360. top2.Dispose ();
  361. }
  362. [Fact]
  363. public void Initialized_Event_Comparing_With_Added_Event ()
  364. {
  365. var top = new Toplevel { Id = "0" }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 80, 25
  366. var winAddedToTop = new Window
  367. {
  368. Id = "t", Width = Dim.Fill (), Height = Dim.Fill ()
  369. }; // Frame: 0, 0, 80, 25; Viewport: 0, 0, 78, 23
  370. var v1AddedToWin = new View
  371. {
  372. Id = "v1", Width = Dim.Fill (), Height = Dim.Fill ()
  373. }; // Frame: 1, 1, 78, 23 (because Windows has a border)
  374. var v2AddedToWin = new View
  375. {
  376. Id = "v2", Width = Dim.Fill (), Height = Dim.Fill ()
  377. }; // Frame: 1, 1, 78, 23 (because Windows has a border)
  378. var svAddedTov1 = new View
  379. {
  380. Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill ()
  381. }; // Frame: 1, 1, 78, 23 (same as it's superview v1AddedToWin)
  382. int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
  383. winAddedToTop.SubViewAdded += (s, e) =>
  384. {
  385. Assert.Equal (e.SuperView.Frame.Width, winAddedToTop.Frame.Width);
  386. Assert.Equal (e.SuperView.Frame.Height, winAddedToTop.Frame.Height);
  387. };
  388. v1AddedToWin.SubViewAdded += (s, e) =>
  389. {
  390. Assert.Equal (e.SuperView.Frame.Width, v1AddedToWin.Frame.Width);
  391. Assert.Equal (e.SuperView.Frame.Height, v1AddedToWin.Frame.Height);
  392. };
  393. v2AddedToWin.SubViewAdded += (s, e) =>
  394. {
  395. Assert.Equal (e.SuperView.Frame.Width, v2AddedToWin.Frame.Width);
  396. Assert.Equal (e.SuperView.Frame.Height, v2AddedToWin.Frame.Height);
  397. };
  398. svAddedTov1.SubViewAdded += (s, e) =>
  399. {
  400. Assert.Equal (e.SuperView.Frame.Width, svAddedTov1.Frame.Width);
  401. Assert.Equal (e.SuperView.Frame.Height, svAddedTov1.Frame.Height);
  402. };
  403. top.Initialized += (s, e) =>
  404. {
  405. tc++;
  406. Assert.Equal (1, tc);
  407. Assert.Equal (1, wc);
  408. Assert.Equal (1, v1c);
  409. Assert.Equal (1, v2c);
  410. Assert.Equal (1, sv1c);
  411. Assert.True (top.CanFocus);
  412. Assert.True (winAddedToTop.CanFocus);
  413. Assert.False (v1AddedToWin.CanFocus);
  414. Assert.False (v2AddedToWin.CanFocus);
  415. Assert.False (svAddedTov1.CanFocus);
  416. top.Layout ();
  417. };
  418. winAddedToTop.Initialized += (s, e) =>
  419. {
  420. wc++;
  421. Assert.Equal (top.Viewport.Width, winAddedToTop.Frame.Width);
  422. Assert.Equal (top.Viewport.Height, winAddedToTop.Frame.Height);
  423. };
  424. v1AddedToWin.Initialized += (s, e) =>
  425. {
  426. v1c++;
  427. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  428. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  429. // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Viewport
  430. // as it is a subview of winAddedToTop, which has a border!
  431. //Assert.Equal (top.Viewport.Width, v1AddedToWin.Frame.Width);
  432. //Assert.Equal (top.Viewport.Height, v1AddedToWin.Frame.Height);
  433. };
  434. v2AddedToWin.Initialized += (s, e) =>
  435. {
  436. v2c++;
  437. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  438. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  439. // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Viewport
  440. // as it is a subview of winAddedToTop, which has a border!
  441. //Assert.Equal (top.Viewport.Width, v2AddedToWin.Frame.Width);
  442. //Assert.Equal (top.Viewport.Height, v2AddedToWin.Frame.Height);
  443. };
  444. svAddedTov1.Initialized += (s, e) =>
  445. {
  446. sv1c++;
  447. // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
  448. // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
  449. // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Viewport
  450. // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of
  451. // winAddedToTop, which has a border!
  452. //Assert.Equal (top.Viewport.Width, svAddedTov1.Frame.Width);
  453. //Assert.Equal (top.Viewport.Height, svAddedTov1.Frame.Height);
  454. Assert.False (svAddedTov1.CanFocus);
  455. //Assert.Throws<InvalidOperationException> (() => svAddedTov1.CanFocus = true);
  456. Assert.False (svAddedTov1.CanFocus);
  457. };
  458. v1AddedToWin.Add (svAddedTov1);
  459. winAddedToTop.Add (v1AddedToWin, v2AddedToWin);
  460. top.Add (winAddedToTop);
  461. top.BeginInit ();
  462. top.EndInit ();
  463. Assert.Equal (1, tc);
  464. Assert.Equal (1, wc);
  465. Assert.Equal (1, v1c);
  466. Assert.Equal (1, v2c);
  467. Assert.Equal (1, sv1c);
  468. Assert.True (top.CanFocus);
  469. Assert.True (winAddedToTop.CanFocus);
  470. Assert.False (v1AddedToWin.CanFocus);
  471. Assert.False (v2AddedToWin.CanFocus);
  472. Assert.False (svAddedTov1.CanFocus);
  473. v1AddedToWin.CanFocus = true;
  474. Assert.False (svAddedTov1.CanFocus); // False because sv1 was disposed and it isn't a subview of v1.
  475. }
  476. [Fact]
  477. public void SuperViewChanged_Raised_On_SubViewAdded_SubViewRemoved ()
  478. {
  479. var isAdded = false;
  480. View superView = new () { Id = "superView" };
  481. View subView = new () { Id = "subView" };
  482. superView.SubViewAdded += (s, e) =>
  483. {
  484. Assert.True (isAdded);
  485. Assert.Equal (superView, subView.SuperView);
  486. Assert.Equal (subView, e.SubView);
  487. Assert.Equal (superView, e.SuperView);
  488. };
  489. superView.SubViewRemoved += (s, e) =>
  490. {
  491. Assert.False (isAdded);
  492. Assert.NotEqual (superView, subView.SuperView);
  493. Assert.Equal (subView, e.SubView);
  494. Assert.Equal (superView, e.SuperView);
  495. };
  496. subView.SuperViewChanged += (s, e) => { isAdded = subView.SuperView == superView; };
  497. superView.Add (subView);
  498. Assert.True (isAdded);
  499. Assert.Equal (superView, subView.SuperView);
  500. Assert.Single (superView.SubViews);
  501. superView.Remove (subView);
  502. Assert.False (isAdded);
  503. Assert.NotEqual (superView, subView.SuperView);
  504. Assert.Empty (superView.SubViews);
  505. }
  506. [Fact]
  507. public void RemoveAll_Removes_All_SubViews ()
  508. {
  509. // Arrange
  510. var superView = new View ();
  511. var subView1 = new View ();
  512. var subView2 = new View ();
  513. var subView3 = new View ();
  514. superView.Add (subView1, subView2, subView3);
  515. // Act
  516. var removedViews = superView.RemoveAll ();
  517. // Assert
  518. Assert.Empty (superView.SubViews);
  519. Assert.Equal (3, removedViews.Count);
  520. Assert.Contains (subView1, removedViews);
  521. Assert.Contains (subView2, removedViews);
  522. Assert.Contains (subView3, removedViews);
  523. }
  524. [Fact]
  525. public void RemoveAllTView_Removes_All_SubViews_Of_Specific_Type ()
  526. {
  527. // Arrange
  528. var superView = new View ();
  529. var subView1 = new View ();
  530. var subView2 = new View ();
  531. var subView3 = new View ();
  532. var subView4 = new Button ();
  533. superView.Add (subView1, subView2, subView3, subView4);
  534. // Act
  535. var removedViews = superView.RemoveAll<Button> ();
  536. // Assert
  537. Assert.Equal (3, superView.SubViews.Count);
  538. Assert.DoesNotContain (subView4, superView.SubViews);
  539. Assert.Single (removedViews);
  540. Assert.Contains (subView4, removedViews);
  541. }
  542. [Fact]
  543. public void RemoveAllTView_Does_Not_Remove_Other_Types ()
  544. {
  545. // Arrange
  546. var superView = new View ();
  547. var subView1 = new View ();
  548. var subView2 = new Button ();
  549. var subView3 = new Label ();
  550. superView.Add (subView1, subView2, subView3);
  551. // Act
  552. var removedViews = superView.RemoveAll<Button> ();
  553. // Assert
  554. Assert.Equal (2, superView.SubViews.Count);
  555. Assert.Contains (subView1, superView.SubViews);
  556. Assert.Contains (subView3, superView.SubViews);
  557. Assert.Single (removedViews);
  558. Assert.Contains (subView2, removedViews);
  559. }
  560. }