Pos.Tests.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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 ()
  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.Absolute (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 PosPercent (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 PosAbsolute_Equal ()
  67. {
  68. var n1 = 0;
  69. var n2 = 0;
  70. Pos pos1 = Pos.Absolute (n1);
  71. Pos pos2 = Pos.Absolute (n2);
  72. Assert.Equal (pos1, pos2);
  73. }
  74. [Fact]
  75. public void PosAbsolute_SetsValue ()
  76. {
  77. Pos pos = Pos.Absolute (0);
  78. Assert.Equal ("Absolute(0)", pos.ToString ());
  79. pos = Pos.Absolute (5);
  80. Assert.Equal ("Absolute(5)", pos.ToString ());
  81. pos = Pos.Absolute (-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 PosPercent (0.10F);
  169. Assert.Equal (10, posFactor.Anchor (100));
  170. var posAnchorEnd = new PosAnchorEnd (1);
  171. Assert.Equal (99, posAnchorEnd.Anchor (100));
  172. var posCenter = new PosCenter ();
  173. Assert.Equal (50, posCenter.Anchor (100));
  174. var posAbsolute = new PosAbsolute (10);
  175. Assert.Equal (10, posAbsolute.Anchor (0));
  176. var posCombine = new 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 PosView (view, Side.Left);
  186. Assert.Equal (20, posViewX.Anchor (0));
  187. var posViewY = new PosView (view, Side.Top);
  188. Assert.Equal (10, posViewY.Anchor (0));
  189. var posRight = new PosView (view, Side.Right);
  190. Assert.Equal (40, posRight.Anchor (0));
  191. var posViewBottom = new PosView (view, 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. void Cleanup (RunState rs)
  215. {
  216. // Cleanup
  217. Application.End (rs);
  218. Application.Top.Dispose ();
  219. // Shutdown must be called to safely clean up Application if Init has been called
  220. Application.Shutdown ();
  221. }
  222. // Test cases:
  223. (Toplevel top, Window win, Button button) app = Setup ();
  224. app.button.Y = Pos.Left (app.win);
  225. RunState rs = Application.Begin (app.top);
  226. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  227. Application.RunLoop (rs);
  228. Cleanup (rs);
  229. app = Setup ();
  230. app.button.Y = Pos.X (app.win);
  231. rs = Application.Begin (app.top);
  232. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  233. Application.RunLoop (rs);
  234. Cleanup (rs);
  235. app = Setup ();
  236. app.button.Y = Pos.Top (app.win);
  237. rs = Application.Begin (app.top);
  238. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  239. Application.RunLoop (rs);
  240. Cleanup (rs);
  241. app = Setup ();
  242. app.button.Y = Pos.Y (app.win);
  243. rs = Application.Begin (app.top);
  244. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  245. Application.RunLoop (rs);
  246. Cleanup (rs);
  247. app = Setup ();
  248. app.button.Y = Pos.Bottom (app.win);
  249. rs = Application.Begin (app.top);
  250. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  251. Application.RunLoop (rs);
  252. Cleanup (rs);
  253. app = Setup ();
  254. app.button.Y = Pos.Right (app.win);
  255. rs = Application.Begin (app.top);
  256. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  257. Application.RunLoop (rs);
  258. Cleanup (rs);
  259. }
  260. [Fact]
  261. public void New_Works ()
  262. {
  263. var pos = new Pos ();
  264. Assert.Equal ("Terminal.Gui.Pos", pos.ToString ());
  265. }
  266. [Fact]
  267. public void PosPercent_Equal ()
  268. {
  269. float n1 = 0;
  270. float n2 = 0;
  271. Pos pos1 = Pos.Percent (n1);
  272. Pos pos2 = Pos.Percent (n2);
  273. Assert.Equal (pos1, pos2);
  274. n1 = n2 = 1;
  275. pos1 = Pos.Percent (n1);
  276. pos2 = Pos.Percent (n2);
  277. Assert.Equal (pos1, pos2);
  278. n1 = n2 = 0.5f;
  279. pos1 = Pos.Percent (n1);
  280. pos2 = Pos.Percent (n2);
  281. Assert.Equal (pos1, pos2);
  282. n1 = n2 = 100f;
  283. pos1 = Pos.Percent (n1);
  284. pos2 = Pos.Percent (n2);
  285. Assert.Equal (pos1, pos2);
  286. n1 = 0;
  287. n2 = 1;
  288. pos1 = Pos.Percent (n1);
  289. pos2 = Pos.Percent (n2);
  290. Assert.NotEqual (pos1, pos2);
  291. n1 = 0.5f;
  292. n2 = 1.5f;
  293. pos1 = Pos.Percent (n1);
  294. pos2 = Pos.Percent (n2);
  295. Assert.NotEqual (pos1, pos2);
  296. }
  297. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  298. // TODO: A new test that calls SetRelativeLayout directly is needed.
  299. [Fact]
  300. [TestRespondersDisposed]
  301. public void Pos_Add_Operator ()
  302. {
  303. Application.Init (new FakeDriver ());
  304. Toplevel top = new ();
  305. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  306. var field = new TextField { X = 0, Y = 0, Width = 20 };
  307. var count = 0;
  308. field.KeyDown += (s, k) =>
  309. {
  310. if (k.KeyCode == KeyCode.Enter)
  311. {
  312. field.Text = $"View {count}";
  313. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  314. view.Add (view2);
  315. Assert.Equal ($"View {count}", view2.Text);
  316. Assert.Equal ($"Absolute({count})", view2.Y.ToString ());
  317. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  318. field.Y += 1;
  319. count++;
  320. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  321. }
  322. };
  323. Application.Iteration += (s, a) =>
  324. {
  325. while (count < 20)
  326. {
  327. field.NewKeyDownEvent (Key.Enter);
  328. }
  329. Application.RequestStop ();
  330. };
  331. var win = new Window ();
  332. win.Add (view);
  333. win.Add (field);
  334. top.Add (win);
  335. Application.Run (top);
  336. Assert.Equal (20, count);
  337. top.Dispose ();
  338. // Shutdown must be called to safely clean up Application if Init has been called
  339. Application.Shutdown ();
  340. }
  341. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  342. // TODO: A new test that calls SetRelativeLayout directly is needed.
  343. [Fact]
  344. [TestRespondersDisposed]
  345. public void Pos_Subtract_Operator ()
  346. {
  347. Application.Init (new FakeDriver ());
  348. Toplevel top = new ();
  349. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  350. var field = new TextField { X = 0, Y = 0, Width = 20 };
  351. var count = 20;
  352. List<View> listViews = new ();
  353. for (var i = 0; i < count; i++)
  354. {
  355. field.Text = $"View {i}";
  356. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  357. view.Add (view2);
  358. Assert.Equal ($"View {i}", view2.Text);
  359. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  360. listViews.Add (view2);
  361. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  362. field.Y += 1;
  363. Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
  364. }
  365. field.KeyDown += (s, k) =>
  366. {
  367. if (k.KeyCode == KeyCode.Enter)
  368. {
  369. Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
  370. view.Remove (listViews [count - 1]);
  371. listViews [count - 1].Dispose ();
  372. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  373. field.Y -= 1;
  374. count--;
  375. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  376. }
  377. };
  378. Application.Iteration += (s, a) =>
  379. {
  380. while (count > 0)
  381. {
  382. field.NewKeyDownEvent (Key.Enter);
  383. }
  384. Application.RequestStop ();
  385. };
  386. var win = new Window ();
  387. win.Add (view);
  388. win.Add (field);
  389. top.Add (win);
  390. Application.Run (top);
  391. Assert.Equal (0, count);
  392. top.Dispose ();
  393. // Shutdown must be called to safely clean up Application if Init has been called
  394. Application.Shutdown ();
  395. }
  396. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  397. // TODO: A new test that calls SetRelativeLayout directly is needed.
  398. [Fact]
  399. public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
  400. {
  401. Application.Init (new FakeDriver ());
  402. Toplevel t = new ();
  403. var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
  404. t.Add (w);
  405. t.Ready += (s, e) =>
  406. {
  407. Assert.Equal (2, w.X = 2);
  408. Assert.Equal (2, w.Y = 2);
  409. };
  410. Application.Iteration += (s, a) => Application.RequestStop ();
  411. Application.Run (t);
  412. t.Dispose ();
  413. Application.Shutdown ();
  414. }
  415. // TODO: Test Left, Top, Right bottom Equal
  416. /// <summary>Tests Pos.Left, Pos.X, Pos.Top, Pos.Y, Pos.Right, and Pos.Bottom set operations</summary>
  417. [Fact]
  418. [TestRespondersDisposed]
  419. public void PosView_Side_SetsValue ()
  420. {
  421. string side; // used in format string
  422. var testRect = Rectangle.Empty;
  423. var testInt = 0;
  424. Pos pos;
  425. // Pos.Left
  426. side = "left";
  427. testInt = 0;
  428. testRect = Rectangle.Empty;
  429. pos = Pos.Left (new ());
  430. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  431. pos = Pos.Left (new () { Frame = testRect });
  432. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  433. testRect = new (1, 2, 3, 4);
  434. pos = Pos.Left (new () { Frame = testRect });
  435. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  436. // Pos.Left(win) + 0
  437. pos = Pos.Left (new () { Frame = testRect }) + testInt;
  438. Assert.Equal (
  439. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  440. pos.ToString ()
  441. );
  442. testInt = 1;
  443. // Pos.Left(win) +1
  444. pos = Pos.Left (new () { Frame = testRect }) + testInt;
  445. Assert.Equal (
  446. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  447. pos.ToString ()
  448. );
  449. testInt = -1;
  450. // Pos.Left(win) -1
  451. pos = Pos.Left (new () { Frame = testRect }) - testInt;
  452. Assert.Equal (
  453. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  454. pos.ToString ()
  455. );
  456. // Pos.X
  457. side = "left";
  458. testInt = 0;
  459. testRect = Rectangle.Empty;
  460. pos = Pos.X (new ());
  461. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  462. pos = Pos.X (new () { Frame = testRect });
  463. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  464. testRect = new (1, 2, 3, 4);
  465. pos = Pos.X (new () { Frame = testRect });
  466. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  467. // Pos.X(win) + 0
  468. pos = Pos.X (new () { Frame = testRect }) + testInt;
  469. Assert.Equal (
  470. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  471. pos.ToString ()
  472. );
  473. testInt = 1;
  474. // Pos.X(win) +1
  475. pos = Pos.X (new () { Frame = testRect }) + testInt;
  476. Assert.Equal (
  477. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  478. pos.ToString ()
  479. );
  480. testInt = -1;
  481. // Pos.X(win) -1
  482. pos = Pos.X (new () { Frame = testRect }) - testInt;
  483. Assert.Equal (
  484. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  485. pos.ToString ()
  486. );
  487. // Pos.Top
  488. side = "top";
  489. testInt = 0;
  490. testRect = Rectangle.Empty;
  491. pos = Pos.Top (new ());
  492. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  493. pos = Pos.Top (new () { Frame = testRect });
  494. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  495. testRect = new (1, 2, 3, 4);
  496. pos = Pos.Top (new () { Frame = testRect });
  497. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  498. // Pos.Top(win) + 0
  499. pos = Pos.Top (new () { Frame = testRect }) + testInt;
  500. Assert.Equal (
  501. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  502. pos.ToString ()
  503. );
  504. testInt = 1;
  505. // Pos.Top(win) +1
  506. pos = Pos.Top (new () { Frame = testRect }) + testInt;
  507. Assert.Equal (
  508. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  509. pos.ToString ()
  510. );
  511. testInt = -1;
  512. // Pos.Top(win) -1
  513. pos = Pos.Top (new () { Frame = testRect }) - testInt;
  514. Assert.Equal (
  515. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  516. pos.ToString ()
  517. );
  518. // Pos.Y
  519. side = "top";
  520. testInt = 0;
  521. testRect = Rectangle.Empty;
  522. pos = Pos.Y (new ());
  523. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  524. pos = Pos.Y (new () { Frame = testRect });
  525. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  526. testRect = new (1, 2, 3, 4);
  527. pos = Pos.Y (new () { Frame = testRect });
  528. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  529. // Pos.Y(win) + 0
  530. pos = Pos.Y (new () { Frame = testRect }) + testInt;
  531. Assert.Equal (
  532. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  533. pos.ToString ()
  534. );
  535. testInt = 1;
  536. // Pos.Y(win) +1
  537. pos = Pos.Y (new () { Frame = testRect }) + testInt;
  538. Assert.Equal (
  539. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  540. pos.ToString ()
  541. );
  542. testInt = -1;
  543. // Pos.Y(win) -1
  544. pos = Pos.Y (new () { Frame = testRect }) - testInt;
  545. Assert.Equal (
  546. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  547. pos.ToString ()
  548. );
  549. // Pos.Bottom
  550. side = "bottom";
  551. testRect = Rectangle.Empty;
  552. testInt = 0;
  553. pos = Pos.Bottom (new ());
  554. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  555. pos = Pos.Bottom (new () { Frame = testRect });
  556. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  557. testRect = new (1, 2, 3, 4);
  558. pos = Pos.Bottom (new () { Frame = testRect });
  559. Assert.Equal ($"View(side={side},target=View(){testRect})", pos.ToString ());
  560. // Pos.Bottom(win) + 0
  561. pos = Pos.Bottom (new () { Frame = testRect }) + testInt;
  562. Assert.Equal (
  563. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  564. pos.ToString ()
  565. );
  566. testInt = 1;
  567. // Pos.Bottom(win) +1
  568. pos = Pos.Bottom (new () { Frame = testRect }) + testInt;
  569. Assert.Equal (
  570. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  571. pos.ToString ()
  572. );
  573. testInt = -1;
  574. // Pos.Bottom(win) -1
  575. pos = Pos.Bottom (new () { Frame = testRect }) - testInt;
  576. Assert.Equal (
  577. $"Combine(View(side={side},target=View(){testRect}){(testInt < 0 ? '-' : '+')}Absolute({testInt}))",
  578. pos.ToString ()
  579. );
  580. #if DEBUG_IDISPOSABLE
  581. // HACK: Force clean up of Responders to avoid having to Dispose all the Views created above.
  582. Responder.Instances.Clear ();
  583. #endif
  584. }
  585. [Fact]
  586. public void PosView_Side_SetToNull_Throws ()
  587. {
  588. Pos pos = Pos.Left (null);
  589. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  590. pos = Pos.X (null);
  591. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  592. pos = Pos.Top (null);
  593. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  594. pos = Pos.Y (null);
  595. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  596. pos = Pos.Bottom (null);
  597. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  598. pos = Pos.Right (null);
  599. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  600. }
  601. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  602. // TODO: A new test that calls SetRelativeLayout directly is needed.
  603. [Fact]
  604. [TestRespondersDisposed]
  605. public void Subtract_Operator ()
  606. {
  607. Application.Init (new FakeDriver ());
  608. Toplevel top = new Toplevel ();
  609. var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
  610. var field = new TextField { X = 0, Y = 0, Width = 20 };
  611. var count = 20;
  612. List<View> listViews = new ();
  613. for (var i = 0; i < count; i++)
  614. {
  615. field.Text = $"View {i}";
  616. var view2 = new View { X = 0, Y = field.Y, Width = 20, Text = field.Text };
  617. view.Add (view2);
  618. Assert.Equal ($"View {i}", view2.Text);
  619. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  620. listViews.Add (view2);
  621. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  622. field.Y += 1;
  623. Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
  624. }
  625. field.KeyDown += (s, k) =>
  626. {
  627. if (k.KeyCode == KeyCode.Enter)
  628. {
  629. Assert.Equal ($"View {count - 1}", listViews [count - 1].Text);
  630. view.Remove (listViews [count - 1]);
  631. listViews [count - 1].Dispose ();
  632. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  633. field.Y -= 1;
  634. count--;
  635. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  636. }
  637. };
  638. Application.Iteration += (s, a) =>
  639. {
  640. while (count > 0)
  641. {
  642. field.NewKeyDownEvent (new Key (KeyCode.Enter));
  643. }
  644. Application.RequestStop ();
  645. };
  646. var win = new Window ();
  647. win.Add (view);
  648. win.Add (field);
  649. top.Add (win);
  650. Application.Run (top);
  651. top.Dispose ();
  652. Assert.Equal (0, count);
  653. // Shutdown must be called to safely clean up Application if Init has been called
  654. Application.Shutdown ();
  655. }
  656. // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved
  657. // TODO: A new test that calls SetRelativeLayout directly is needed.
  658. [Fact]
  659. public void Validation_Does_Not_Throw_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
  660. {
  661. Application.Init (new FakeDriver ());
  662. Toplevel t = new Toplevel ();
  663. var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
  664. t.Add (w);
  665. t.Ready += (s, e) =>
  666. {
  667. Assert.Equal (2, w.X = 2);
  668. Assert.Equal (2, w.Y = 2);
  669. };
  670. Application.Iteration += (s, a) => Application.RequestStop ();
  671. Application.Run (t);
  672. t.Dispose ();
  673. Application.Shutdown ();
  674. }
  675. [Fact]
  676. [SetupFakeDriver]
  677. public void PosCombine_DimCombine_View_With_SubViews ()
  678. {
  679. Toplevel top = new Toplevel () { Width = 80, Height = 25 };
  680. var win1 = new Window { Id = "win1", Width = 20, Height = 10 };
  681. var view1 = new View
  682. {
  683. Text = "view1",
  684. Width = Auto (DimAutoStyle.Text),
  685. Height = Auto (DimAutoStyle.Text)
  686. };
  687. var win2 = new Window { Id = "win2", Y = Pos.Bottom (view1) + 1, Width = 10, Height = 3 };
  688. var view2 = new View { Id = "view2", Width = Dim.Fill (), Height = 1, CanFocus = true };
  689. var view3 = new View { Id = "view3", Width = Dim.Fill (1), Height = 1, CanFocus = true };
  690. view2.Add (view3);
  691. win2.Add (view2);
  692. win1.Add (view1, win2);
  693. top.Add (win1);
  694. top.BeginInit ();
  695. top.EndInit ();
  696. Assert.Equal (new Rectangle (0, 0, 80, 25), top.Frame);
  697. Assert.Equal (new Rectangle (0, 0, 5, 1), view1.Frame);
  698. Assert.Equal (new Rectangle (0, 0, 20, 10), win1.Frame);
  699. Assert.Equal (new Rectangle (0, 2, 10, 3), win2.Frame);
  700. Assert.Equal (new Rectangle (0, 0, 8, 1), view2.Frame);
  701. Assert.Equal (new Rectangle (0, 0, 7, 1), view3.Frame);
  702. var foundView = View.FindDeepestView (top, new (9, 4));
  703. Assert.Equal (foundView, view2);
  704. }
  705. [Fact]
  706. public void PosCombine_Refs_SuperView_Throws ()
  707. {
  708. Application.Init (new FakeDriver ());
  709. var top = new Toplevel ();
  710. var w = new Window { X = Pos.Left (top) + 2, Y = Pos.Top (top) + 2 };
  711. var f = new FrameView ();
  712. var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
  713. var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
  714. f.Add (v1, v2);
  715. w.Add (f);
  716. top.Add (w);
  717. Application.Begin (top);
  718. f.X = Pos.X (Application.Top) + Pos.X (v2) - Pos.X (v1);
  719. f.Y = Pos.Y (Application.Top) + Pos.Y (v2) - Pos.Y (v1);
  720. Application.Top.LayoutComplete += (s, e) =>
  721. {
  722. Assert.Equal (0, Application.Top.Frame.X);
  723. Assert.Equal (0, Application.Top.Frame.Y);
  724. Assert.Equal (2, w.Frame.X);
  725. Assert.Equal (2, w.Frame.Y);
  726. Assert.Equal (2, f.Frame.X);
  727. Assert.Equal (2, f.Frame.Y);
  728. Assert.Equal (4, v1.Frame.X);
  729. Assert.Equal (4, v1.Frame.Y);
  730. Assert.Equal (6, v2.Frame.X);
  731. Assert.Equal (6, v2.Frame.Y);
  732. };
  733. Application.Iteration += (s, a) => Application.RequestStop ();
  734. Assert.Throws<InvalidOperationException> (() => Application.Run ());
  735. top.Dispose ();
  736. Application.Shutdown ();
  737. }
  738. }