PosTests.cs 32 KB

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