PosTests.cs 30 KB

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