Pos.Tests.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. using Xunit.Abstractions;
  2. using static Terminal.Gui.Dim;
  3. using static Terminal.Gui.Pos;
  4. namespace Terminal.Gui.PosDimTests;
  5. public class PosTests (ITestOutputHelper output)
  6. {
  7. // Was named AutoSize_Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
  8. // but doesn't actually have anything to do with AutoSize.
  9. [Fact]
  10. public void
  11. Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
  12. {
  13. Application.Init (new FakeDriver ());
  14. Toplevel t = new ();
  15. var w = new Window { X = Pos.Left (t) + 2, Y = Pos.At (2) };
  16. var v = new View { X = Pos.Center (), Y = Pos.Percent (10) };
  17. w.Add (v);
  18. t.Add (w);
  19. t.Ready += (s, e) =>
  20. {
  21. v.Frame = new Rectangle (2, 2, 10, 10);
  22. Assert.Equal (2, v.X = 2);
  23. Assert.Equal (2, v.Y = 2);
  24. };
  25. Application.Iteration += (s, a) => Application.RequestStop ();
  26. Application.Run (t);
  27. t.Dispose ();
  28. Application.Shutdown ();
  29. }
  30. [Fact]
  31. public void PosAbsolute_Calculate_ReturnsExpectedValue ()
  32. {
  33. var posAbsolute = new PosAbsolute (5);
  34. var result = posAbsolute.Calculate (10, new DimAbsolute (2), null, Dimension.None);
  35. Assert.Equal (5, result);
  36. }
  37. [Fact]
  38. public void PosCombine_Calculate_ReturnsExpectedValue ()
  39. {
  40. var posCombine = new PosCombine (true, new PosAbsolute (5), new PosAbsolute (3));
  41. var result = posCombine.Calculate (10, new DimAbsolute (2), null, Dimension.None);
  42. Assert.Equal (8, result);
  43. }
  44. [Fact]
  45. public void PosFactor_Calculate_ReturnsExpectedValue ()
  46. {
  47. var posFactor = new PosFactor (0.5f);
  48. var result = posFactor.Calculate (10, new DimAbsolute (2), null, Dimension.None);
  49. Assert.Equal (5, result);
  50. }
  51. [Fact]
  52. public void PosFunc_Calculate_ReturnsExpectedValue ()
  53. {
  54. var posFunc = new PosFunc (() => 5);
  55. var result = posFunc.Calculate (10, new DimAbsolute (2), null, Dimension.None);
  56. Assert.Equal (5, result);
  57. }
  58. [Fact]
  59. public void PosView_Calculate_ReturnsExpectedValue ()
  60. {
  61. var posView = new PosView (new View { Frame = new Rectangle (5, 5, 10, 10) }, 0);
  62. var result = posView.Calculate (10, new DimAbsolute (2), null, Dimension.None);
  63. Assert.Equal (5, result);
  64. }
  65. [Fact]
  66. public void PosAt_Equal ()
  67. {
  68. var n1 = 0;
  69. var n2 = 0;
  70. Pos pos1 = Pos.At (n1);
  71. Pos pos2 = Pos.At (n2);
  72. Assert.Equal (pos1, pos2);
  73. }
  74. [Fact]
  75. public void PosAt_SetsValue ()
  76. {
  77. Pos pos = Pos.At (0);
  78. Assert.Equal ("Absolute(0)", pos.ToString ());
  79. pos = Pos.At (5);
  80. Assert.Equal ("Absolute(5)", pos.ToString ());
  81. pos = Pos.At (-1);
  82. Assert.Equal ("Absolute(-1)", pos.ToString ());
  83. }
  84. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  85. // TODO: A new test that calls SetRelativeLayout directly is needed.
  86. [Fact]
  87. [TestRespondersDisposed]
  88. public void PosCombine_WHY_Throws ()
  89. {
  90. Application.Init (new FakeDriver ());
  91. Toplevel t = new Toplevel();
  92. var w = new Window { X = Pos.Left (t) + 2, Y = Pos.Top (t) + 2 };
  93. var f = new FrameView ();
  94. var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
  95. var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
  96. f.Add (v1); // v2 not added
  97. w.Add (f);
  98. t.Add (w);
  99. f.X = Pos.X (v2) - Pos.X (v1);
  100. f.Y = Pos.Y (v2) - Pos.Y (v1);
  101. Assert.Throws<InvalidOperationException> (() => Application.Run (t));
  102. t.Dispose ();
  103. Application.Shutdown ();
  104. v2.Dispose ();
  105. }
  106. [Fact]
  107. public void PosCombine_DoesNotReturn ()
  108. {
  109. var v = new View { Id = "V" };
  110. Pos pos = Pos.Left (v);
  111. Assert.Equal (
  112. $"View(side=left,target=View(V){v.Frame})",
  113. pos.ToString ()
  114. );
  115. pos = Pos.X (v);
  116. Assert.Equal (
  117. $"View(side=left,target=View(V){v.Frame})",
  118. pos.ToString ()
  119. );
  120. pos = Pos.Top (v);
  121. Assert.Equal (
  122. $"View(side=top,target=View(V){v.Frame})",
  123. pos.ToString ()
  124. );
  125. pos = Pos.Y (v);
  126. Assert.Equal (
  127. $"View(side=top,target=View(V){v.Frame})",
  128. pos.ToString ()
  129. );
  130. pos = Pos.Right (v);
  131. Assert.Equal (
  132. $"View(side=right,target=View(V){v.Frame})",
  133. pos.ToString ()
  134. );
  135. pos = Pos.Bottom (v);
  136. Assert.Equal (
  137. $"View(side=bottom,target=View(V){v.Frame})",
  138. pos.ToString ()
  139. );
  140. }
  141. [Fact]
  142. public void PosFunction_Equal ()
  143. {
  144. Func<int> f1 = () => 0;
  145. Func<int> f2 = () => 0;
  146. Pos pos1 = Pos.Function (f1);
  147. Pos pos2 = Pos.Function (f2);
  148. Assert.Equal (pos1, pos2);
  149. f2 = () => 1;
  150. pos2 = Pos.Function (f2);
  151. Assert.NotEqual (pos1, pos2);
  152. }
  153. [Fact]
  154. public void PosFunction_SetsValue ()
  155. {
  156. var text = "Test";
  157. Pos pos = Pos.Function (() => text.Length);
  158. Assert.Equal ("PosFunc(4)", pos.ToString ());
  159. text = "New Test";
  160. Assert.Equal ("PosFunc(8)", pos.ToString ());
  161. text = "";
  162. Assert.Equal ("PosFunc(0)", pos.ToString ());
  163. }
  164. [Fact]
  165. [TestRespondersDisposed]
  166. public void Internal_Tests ()
  167. {
  168. var posFactor = new Pos.PosFactor (0.10F);
  169. Assert.Equal (10, posFactor.Anchor (100));
  170. var posAnchorEnd = new Pos.PosAnchorEnd (1);
  171. Assert.Equal (99, posAnchorEnd.Anchor (100));
  172. var posCenter = new Pos.PosCenter ();
  173. Assert.Equal (50, posCenter.Anchor (100));
  174. var posAbsolute = new Pos.PosAbsolute (10);
  175. Assert.Equal (10, posAbsolute.Anchor (0));
  176. var posCombine = new Pos.PosCombine (true, posFactor, posAbsolute);
  177. Assert.Equal (posCombine._left, posFactor);
  178. Assert.Equal (posCombine._right, posAbsolute);
  179. Assert.Equal (20, posCombine.Anchor (100));
  180. posCombine = new (true, posAbsolute, posFactor);
  181. Assert.Equal (posCombine._left, posAbsolute);
  182. Assert.Equal (posCombine._right, posFactor);
  183. Assert.Equal (20, posCombine.Anchor (100));
  184. var view = new View { Frame = new (20, 10, 20, 1) };
  185. var posViewX = new Pos.PosView (view, Pos.Side.Left);
  186. Assert.Equal (20, posViewX.Anchor (0));
  187. var posViewY = new Pos.PosView (view, Pos.Side.Top);
  188. Assert.Equal (10, posViewY.Anchor (0));
  189. var posRight = new Pos.PosView (view, Pos.Side.Right);
  190. Assert.Equal (40, posRight.Anchor (0));
  191. var posViewBottom = new Pos.PosView (view, Pos.Side.Bottom);
  192. Assert.Equal (11, posViewBottom.Anchor (0));
  193. view.Dispose ();
  194. }
  195. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  196. // TODO: A new test that calls SetRelativeLayout directly is needed.
  197. // See: https://github.com/gui-cs/Terminal.Gui/issues/504
  198. [Fact]
  199. [TestRespondersDisposed]
  200. public void LeftTopBottomRight_Win_ShouldNotThrow ()
  201. {
  202. // Setup Fake driver
  203. (Toplevel top, Window win, Button button) setup ()
  204. {
  205. Application.Init (new FakeDriver ());
  206. Application.Iteration += (s, a) => { Application.RequestStop (); };
  207. var win = new Window { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
  208. var top = new Toplevel ();
  209. top.Add (win);
  210. var button = new Button { X = Pos.Center (), Text = "button" };
  211. win.Add (button);
  212. return (top, win, button);
  213. }
  214. RunState rs;
  215. void cleanup (RunState rs)
  216. {
  217. // Cleanup
  218. Application.End (rs);
  219. Application.Top.Dispose ();
  220. // Shutdown must be called to safely clean up Application if Init has been called
  221. Application.Shutdown ();
  222. }
  223. // Test cases:
  224. (Toplevel top, Window win, Button button) app = setup ();
  225. app.button.Y = Pos.Left (app.win);
  226. rs = Application.Begin (app.top);
  227. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  228. Application.RunLoop (rs);
  229. cleanup (rs);
  230. app = setup ();
  231. app.button.Y = Pos.X (app.win);
  232. rs = Application.Begin (app.top);
  233. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  234. Application.RunLoop (rs);
  235. cleanup (rs);
  236. app = setup ();
  237. app.button.Y = Pos.Top (app.win);
  238. rs = Application.Begin (app.top);
  239. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  240. Application.RunLoop (rs);
  241. cleanup (rs);
  242. app = setup ();
  243. app.button.Y = Pos.Y (app.win);
  244. rs = Application.Begin (app.top);
  245. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  246. Application.RunLoop (rs);
  247. cleanup (rs);
  248. app = setup ();
  249. app.button.Y = Pos.Bottom (app.win);
  250. rs = Application.Begin (app.top);
  251. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  252. Application.RunLoop (rs);
  253. cleanup (rs);
  254. app = setup ();
  255. app.button.Y = Pos.Right (app.win);
  256. rs = Application.Begin (app.top);
  257. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  258. Application.RunLoop (rs);
  259. cleanup (rs);
  260. }
  261. [Fact]
  262. public void New_Works ()
  263. {
  264. var pos = new Pos ();
  265. Assert.Equal ("Terminal.Gui.Pos", pos.ToString ());
  266. }
  267. [Fact]
  268. public void PosPercent_Equal ()
  269. {
  270. float n1 = 0;
  271. float n2 = 0;
  272. Pos pos1 = Pos.Percent (n1);
  273. Pos pos2 = Pos.Percent (n2);
  274. Assert.Equal (pos1, pos2);
  275. n1 = n2 = 1;
  276. pos1 = Pos.Percent (n1);
  277. pos2 = Pos.Percent (n2);
  278. Assert.Equal (pos1, pos2);
  279. n1 = n2 = 0.5f;
  280. pos1 = Pos.Percent (n1);
  281. pos2 = Pos.Percent (n2);
  282. Assert.Equal (pos1, pos2);
  283. n1 = n2 = 100f;
  284. pos1 = Pos.Percent (n1);
  285. pos2 = Pos.Percent (n2);
  286. Assert.Equal (pos1, pos2);
  287. n1 = 0;
  288. n2 = 1;
  289. pos1 = Pos.Percent (n1);
  290. pos2 = Pos.Percent (n2);
  291. Assert.NotEqual (pos1, pos2);
  292. n1 = 0.5f;
  293. n2 = 1.5f;
  294. pos1 = Pos.Percent (n1);
  295. pos2 = Pos.Percent (n2);
  296. Assert.NotEqual (pos1, pos2);
  297. }
  298. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  299. // TODO: A new test that calls SetRelativeLayout directly is needed.
  300. [Fact]
  301. [TestRespondersDisposed]
  302. public void Pos_Add_Operator ()
  303. {
  304. Application.Init (new FakeDriver ());
  305. Toplevel top = new ();
  306. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  307. var field = new TextField { X = 0, Y = 0, Width = 20 };
  308. var count = 0;
  309. field.KeyDown += (s, k) =>
  310. {
  311. if (k.KeyCode == KeyCode.Enter)
  312. {
  313. field.Text = $"View {count}";
  314. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  315. view.Add (view2);
  316. Assert.Equal ($"View {count}", view2.Text);
  317. Assert.Equal ($"Absolute({count})", view2.Y.ToString ());
  318. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  319. field.Y += 1;
  320. count++;
  321. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  322. }
  323. };
  324. Application.Iteration += (s, a) =>
  325. {
  326. while (count < 20)
  327. {
  328. field.NewKeyDownEvent (Key.Enter);
  329. }
  330. Application.RequestStop ();
  331. };
  332. var win = new Window ();
  333. win.Add (view);
  334. win.Add (field);
  335. top.Add (win);
  336. Application.Run (top);
  337. Assert.Equal (20, count);
  338. top.Dispose ();
  339. // Shutdown must be called to safely clean up Application if Init has been called
  340. Application.Shutdown ();
  341. }
  342. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  343. // TODO: A new test that calls SetRelativeLayout directly is needed.
  344. [Fact]
  345. [TestRespondersDisposed]
  346. public void Pos_Subtract_Operator ()
  347. {
  348. Application.Init (new FakeDriver ());
  349. Toplevel top = new ();
  350. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  351. var field = new TextField { X = 0, Y = 0, Width = 20 };
  352. var count = 20;
  353. List<View> listViews = new ();
  354. for (var i = 0; i < count; i++)
  355. {
  356. field.Text = $"View {i}";
  357. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  358. view.Add (view2);
  359. Assert.Equal ($"View {i}", view2.Text);
  360. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  361. listViews.Add (view2);
  362. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  363. field.Y += 1;
  364. Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
  365. }
  366. field.KeyDown += (s, k) =>
  367. {
  368. if (k.KeyCode == KeyCode.Enter)
  369. {
  370. Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
  371. view.Remove (listViews [count - 1]);
  372. listViews [count - 1].Dispose ();
  373. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  374. field.Y -= 1;
  375. count--;
  376. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  377. }
  378. };
  379. Application.Iteration += (s, a) =>
  380. {
  381. while (count > 0)
  382. {
  383. field.NewKeyDownEvent (Key.Enter);
  384. }
  385. Application.RequestStop ();
  386. };
  387. var win = new Window ();
  388. win.Add (view);
  389. win.Add (field);
  390. top.Add (win);
  391. Application.Run (top);
  392. Assert.Equal (0, count);
  393. top.Dispose ();
  394. // Shutdown must be called to safely clean up Application if Init has been called
  395. Application.Shutdown ();
  396. }
  397. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  398. // TODO: A new test that calls SetRelativeLayout directly is needed.
  399. [Fact]
  400. public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
  401. {
  402. Application.Init (new FakeDriver ());
  403. Toplevel t = new ();
  404. var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
  405. t.Add (w);
  406. t.Ready += (s, e) =>
  407. {
  408. Assert.Equal (2, w.X = 2);
  409. Assert.Equal (2, w.Y = 2);
  410. };
  411. Application.Iteration += (s, a) => Application.RequestStop ();
  412. Application.Run (t);
  413. t.Dispose ();
  414. Application.Shutdown ();
  415. }
  416. // TODO: Test Left, Top, Right bottom Equal
  417. /// <summary>Tests Pos.Left, Pos.X, Pos.Top, Pos.Y, Pos.Right, and Pos.Bottom set operations</summary>
  418. [Fact]
  419. [TestRespondersDisposed]
  420. public void PosView_Side_SetsValue ()
  421. {
  422. string side; // used in format string
  423. var testRect = Rectangle.Empty;
  424. var testInt = 0;
  425. Pos pos;
  426. // Pos.Left
  427. side = "left";
  428. testInt = 0;
  429. testRect = Rectangle.Empty;
  430. pos = Pos.Left (new ());
  431. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  432. pos = Pos.Left (new() { Frame = testRect });
  433. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  434. testRect = new (1, 2, 3, 4);
  435. pos = Pos.Left (new() { Frame = testRect });
  436. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  437. // Pos.Left(win) + 0
  438. pos = Pos.Left (new() { Frame = testRect }) + testInt;
  439. Assert.Equal (
  440. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  441. pos.ToString ()
  442. );
  443. testInt = 1;
  444. // Pos.Left(win) +1
  445. pos = Pos.Left (new() { Frame = testRect }) + testInt;
  446. Assert.Equal (
  447. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  448. pos.ToString ()
  449. );
  450. testInt = -1;
  451. // Pos.Left(win) -1
  452. pos = Pos.Left (new() { Frame = testRect }) - testInt;
  453. Assert.Equal (
  454. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  455. pos.ToString ()
  456. );
  457. // Pos.X
  458. side = "left";
  459. testInt = 0;
  460. testRect = Rectangle.Empty;
  461. pos = Pos.X (new ());
  462. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  463. pos = Pos.X (new() { Frame = testRect });
  464. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  465. testRect = new (1, 2, 3, 4);
  466. pos = Pos.X (new() { Frame = testRect });
  467. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  468. // Pos.X(win) + 0
  469. pos = Pos.X (new() { Frame = testRect }) + testInt;
  470. Assert.Equal (
  471. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  472. pos.ToString ()
  473. );
  474. testInt = 1;
  475. // Pos.X(win) +1
  476. pos = Pos.X (new() { Frame = testRect }) + testInt;
  477. Assert.Equal (
  478. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  479. pos.ToString ()
  480. );
  481. testInt = -1;
  482. // Pos.X(win) -1
  483. pos = Pos.X (new() { Frame = testRect }) - testInt;
  484. Assert.Equal (
  485. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  486. pos.ToString ()
  487. );
  488. // Pos.Top
  489. side = "top";
  490. testInt = 0;
  491. testRect = Rectangle.Empty;
  492. pos = Pos.Top (new ());
  493. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  494. pos = Pos.Top (new() { Frame = testRect });
  495. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  496. testRect = new (1, 2, 3, 4);
  497. pos = Pos.Top (new() { Frame = testRect });
  498. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  499. // Pos.Top(win) + 0
  500. pos = Pos.Top (new() { Frame = testRect }) + testInt;
  501. Assert.Equal (
  502. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  503. pos.ToString ()
  504. );
  505. testInt = 1;
  506. // Pos.Top(win) +1
  507. pos = Pos.Top (new() { Frame = testRect }) + testInt;
  508. Assert.Equal (
  509. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  510. pos.ToString ()
  511. );
  512. testInt = -1;
  513. // Pos.Top(win) -1
  514. pos = Pos.Top (new() { Frame = testRect }) - testInt;
  515. Assert.Equal (
  516. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  517. pos.ToString ()
  518. );
  519. // Pos.Y
  520. side = "top";
  521. testInt = 0;
  522. testRect = Rectangle.Empty;
  523. pos = Pos.Y (new ());
  524. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  525. pos = Pos.Y (new() { Frame = testRect });
  526. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  527. testRect = new (1, 2, 3, 4);
  528. pos = Pos.Y (new() { Frame = testRect });
  529. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  530. // Pos.Y(win) + 0
  531. pos = Pos.Y (new() { Frame = testRect }) + testInt;
  532. Assert.Equal (
  533. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  534. pos.ToString ()
  535. );
  536. testInt = 1;
  537. // Pos.Y(win) +1
  538. pos = Pos.Y (new() { Frame = testRect }) + testInt;
  539. Assert.Equal (
  540. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  541. pos.ToString ()
  542. );
  543. testInt = -1;
  544. // Pos.Y(win) -1
  545. pos = Pos.Y (new() { Frame = testRect }) - testInt;
  546. Assert.Equal (
  547. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  548. pos.ToString ()
  549. );
  550. // Pos.Bottom
  551. side = "bottom";
  552. testRect = Rectangle.Empty;
  553. testInt = 0;
  554. pos = Pos.Bottom (new ());
  555. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  556. pos = Pos.Bottom (new() { Frame = testRect });
  557. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  558. testRect = new (1, 2, 3, 4);
  559. pos = Pos.Bottom (new() { Frame = testRect });
  560. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  561. // Pos.Bottom(win) + 0
  562. pos = Pos.Bottom (new() { Frame = testRect }) + testInt;
  563. Assert.Equal (
  564. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  565. pos.ToString ()
  566. );
  567. testInt = 1;
  568. // Pos.Bottom(win) +1
  569. pos = Pos.Bottom (new() { Frame = testRect }) + testInt;
  570. Assert.Equal (
  571. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  572. pos.ToString ()
  573. );
  574. testInt = -1;
  575. // Pos.Bottom(win) -1
  576. pos = Pos.Bottom (new() { Frame = testRect }) - testInt;
  577. Assert.Equal (
  578. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  579. pos.ToString ()
  580. );
  581. #if DEBUG_IDISPOSABLE
  582. // HACK: Force clean up of Responders to avoid having to Dispose all the Views created above.
  583. Responder.Instances.Clear ();
  584. #endif
  585. }
  586. [Fact]
  587. public void PosView_Side_SetToNull_Throws ()
  588. {
  589. Pos pos = Pos.Left (null);
  590. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  591. pos = Pos.X (null);
  592. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  593. pos = Pos.Top (null);
  594. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  595. pos = Pos.Y (null);
  596. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  597. pos = Pos.Bottom (null);
  598. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  599. pos = Pos.Right (null);
  600. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  601. }
  602. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  603. // TODO: A new test that calls SetRelativeLayout directly is needed.
  604. [Fact]
  605. [TestRespondersDisposed]
  606. public void Subtract_Operator ()
  607. {
  608. Application.Init (new FakeDriver ());
  609. Toplevel top = new Toplevel ();
  610. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  611. var field = new TextField { X = 0, Y = 0, Width = 20 };
  612. var count = 20;
  613. List<View> listViews = new ();
  614. for (var i = 0; i < count; i++)
  615. {
  616. field.Text = $"View {i}";
  617. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  618. view.Add (view2);
  619. Assert.Equal ($"View {i}", view2.Text);
  620. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  621. listViews.Add (view2);
  622. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  623. field.Y += 1;
  624. Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
  625. }
  626. field.KeyDown += (s, k) =>
  627. {
  628. if (k.KeyCode == KeyCode.Enter)
  629. {
  630. Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
  631. view.Remove (listViews [count - 1]);
  632. listViews [count - 1].Dispose ();
  633. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  634. field.Y -= 1;
  635. count--;
  636. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  637. }
  638. };
  639. Application.Iteration += (s, a) =>
  640. {
  641. while (count > 0)
  642. {
  643. field.NewKeyDownEvent (new Key (KeyCode.Enter));
  644. }
  645. Application.RequestStop ();
  646. };
  647. var win = new Window ();
  648. win.Add (view);
  649. win.Add (field);
  650. top.Add (win);
  651. Application.Run (top);
  652. top.Dispose ();
  653. Assert.Equal (0, count);
  654. // Shutdown must be called to safely clean up Application if Init has been called
  655. Application.Shutdown ();
  656. }
  657. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  658. // TODO: A new test that calls SetRelativeLayout directly is needed.
  659. [Fact]
  660. public void Validation_Does_Not_Throw_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
  661. {
  662. Application.Init (new FakeDriver ());
  663. Toplevel t = new Toplevel ();
  664. var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
  665. t.Add (w);
  666. t.Ready += (s, e) =>
  667. {
  668. Assert.Equal (2, w.X = 2);
  669. Assert.Equal (2, w.Y = 2);
  670. };
  671. Application.Iteration += (s, a) => Application.RequestStop ();
  672. Application.Run (t);
  673. t.Dispose ();
  674. Application.Shutdown ();
  675. }
  676. [Fact]
  677. [SetupFakeDriver]
  678. public void PosCombine_DimCombine_View_With_SubViews ()
  679. {
  680. var clicked = false;
  681. Toplevel top = new Toplevel () { Width = 80, Height = 25 };
  682. var win1 = new Window { Id = "win1", Width = 20, Height = 10 };
  683. var view1 = new View
  684. {
  685. Text = "view1",
  686. Width = Auto (DimAutoStyle.Text),
  687. Height = Auto (DimAutoStyle.Text)
  688. };
  689. var win2 = new Window { Id = "win2", Y = Pos.Bottom (view1) + 1, Width = 10, Height = 3 };
  690. var view2 = new View { Id = "view2", Width = Dim.Fill (), Height = 1, CanFocus = true };
  691. view2.MouseClick += (sender, e) => clicked = true;
  692. var view3 = new View { Id = "view3", Width = Dim.Fill (1), Height = 1, CanFocus = true };
  693. view2.Add (view3);
  694. win2.Add (view2);
  695. win1.Add (view1, win2);
  696. top.Add (win1);
  697. top.BeginInit ();
  698. top.EndInit ();
  699. Assert.Equal (new Rectangle (0, 0, 80, 25), top.Frame);
  700. Assert.Equal (new Rectangle (0, 0, 5, 1), view1.Frame);
  701. Assert.Equal (new Rectangle (0, 0, 20, 10), win1.Frame);
  702. Assert.Equal (new Rectangle (0, 2, 10, 3), win2.Frame);
  703. Assert.Equal (new Rectangle (0, 0, 8, 1), view2.Frame);
  704. Assert.Equal (new Rectangle (0, 0, 7, 1), view3.Frame);
  705. var foundView = View.FindDeepestView (top, 9, 4);
  706. Assert.Equal (foundView, view2);
  707. }
  708. [Fact]
  709. public void PosCombine_Refs_SuperView_Throws ()
  710. {
  711. Application.Init (new FakeDriver ());
  712. var top = new Toplevel ();
  713. var w = new Window { X = Pos.Left (top) + 2, Y = Pos.Top (top) + 2 };
  714. var f = new FrameView ();
  715. var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
  716. var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
  717. f.Add (v1, v2);
  718. w.Add (f);
  719. top.Add (w);
  720. Application.Begin (top);
  721. f.X = Pos.X (Application.Top) + Pos.X (v2) - Pos.X (v1);
  722. f.Y = Pos.Y (Application.Top) + Pos.Y (v2) - Pos.Y (v1);
  723. Application.Top.LayoutComplete += (s, e) =>
  724. {
  725. Assert.Equal (0, Application.Top.Frame.X);
  726. Assert.Equal (0, Application.Top.Frame.Y);
  727. Assert.Equal (2, w.Frame.X);
  728. Assert.Equal (2, w.Frame.Y);
  729. Assert.Equal (2, f.Frame.X);
  730. Assert.Equal (2, f.Frame.Y);
  731. Assert.Equal (4, v1.Frame.X);
  732. Assert.Equal (4, v1.Frame.Y);
  733. Assert.Equal (6, v2.Frame.X);
  734. Assert.Equal (6, v2.Frame.Y);
  735. };
  736. Application.Iteration += (s, a) => Application.RequestStop ();
  737. Assert.Throws<InvalidOperationException> (() => Application.Run ());
  738. top.Dispose ();
  739. Application.Shutdown ();
  740. }
  741. }