PosTests.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.IO;
  6. using System.Linq;
  7. using Terminal.Gui;
  8. using Xunit;
  9. using Xunit.Abstractions;
  10. // Alias Console to MockConsole so we don't accidentally use Console
  11. using Console = Terminal.Gui.FakeConsole;
  12. namespace Terminal.Gui.ViewTests {
  13. public class LayoutTests_PosTests {
  14. readonly ITestOutputHelper output;
  15. public LayoutTests_PosTests (ITestOutputHelper output)
  16. {
  17. this.output = output;
  18. }
  19. [Fact]
  20. public void New_Works ()
  21. {
  22. var pos = new Pos ();
  23. Assert.Equal ("Terminal.Gui.Pos", pos.ToString ());
  24. }
  25. [Fact]
  26. public void AnchorEnd_SetsValue ()
  27. {
  28. var n = 0;
  29. var pos = Pos.AnchorEnd ();
  30. Assert.Equal ($"AnchorEnd({n})", pos.ToString ());
  31. n = 5;
  32. pos = Pos.AnchorEnd (n);
  33. Assert.Equal ($"AnchorEnd({n})", pos.ToString ());
  34. }
  35. [Fact]
  36. public void AnchorEnd_Equal ()
  37. {
  38. var n1 = 0;
  39. var n2 = 0;
  40. var pos1 = Pos.AnchorEnd (n1);
  41. var pos2 = Pos.AnchorEnd (n2);
  42. Assert.Equal (pos1, pos2);
  43. // Test inequality
  44. n2 = 5;
  45. pos2 = Pos.AnchorEnd (n2);
  46. Assert.NotEqual (pos1, pos2);
  47. }
  48. [Fact]
  49. [AutoInitShutdown]
  50. public void AnchorEnd_Equal_Inside_Window ()
  51. {
  52. var viewWidth = 10;
  53. var viewHeight = 1;
  54. var tv = new TextView () {
  55. X = Pos.AnchorEnd (viewWidth),
  56. Y = Pos.AnchorEnd (viewHeight),
  57. Width = viewWidth,
  58. Height = viewHeight
  59. };
  60. var win = new Window ();
  61. win.Add (tv);
  62. var top = Application.Top;
  63. top.Add (win);
  64. Application.Begin (top);
  65. Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
  66. Assert.Equal (new Rect (0, 0, 80, 25), win.Frame);
  67. Assert.Equal (new Rect (68, 22, 10, 1), tv.Frame);
  68. }
  69. [Fact]
  70. [AutoInitShutdown]
  71. public void AnchorEnd_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
  72. {
  73. var viewWidth = 10;
  74. var viewHeight = 1;
  75. var tv = new TextView () {
  76. X = Pos.AnchorEnd (viewWidth),
  77. Y = Pos.AnchorEnd (viewHeight),
  78. Width = viewWidth,
  79. Height = viewHeight
  80. };
  81. var win = new Window ();
  82. win.Add (tv);
  83. var menu = new MenuBar ();
  84. var status = new StatusBar ();
  85. var top = Application.Top;
  86. top.Add (win, menu, status);
  87. Application.Begin (top);
  88. Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
  89. Assert.Equal (new Rect (0, 0, 80, 1), menu.Frame);
  90. Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
  91. Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
  92. Assert.Equal (new Rect (68, 20, 10, 1), tv.Frame);
  93. }
  94. [Fact]
  95. [AutoInitShutdown]
  96. public void Bottom_Equal_Inside_Window ()
  97. {
  98. var win = new Window ();
  99. var label = new Label ("This should be the last line.") {
  100. TextAlignment = TextAlignment.Centered,
  101. ColorScheme = Colors.Menu,
  102. Width = Dim.Fill (),
  103. X = Pos.Center (),
  104. Y = Pos.Bottom (win) - 3 // two lines top and bottom borders more one line above the bottom border
  105. };
  106. win.Add (label);
  107. var top = Application.Top;
  108. top.Add (win);
  109. Application.Begin (top);
  110. ((FakeDriver)Application.Driver).SetBufferSize (40, 10);
  111. Assert.True (label.AutoSize);
  112. Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
  113. Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
  114. Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
  115. var expected = @"
  116. ┌──────────────────────────────────────┐
  117. │ │
  118. │ │
  119. │ │
  120. │ │
  121. │ │
  122. │ │
  123. │ │
  124. │ This should be the last line. │
  125. └──────────────────────────────────────┘
  126. ";
  127. TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  128. }
  129. [Fact]
  130. [AutoInitShutdown]
  131. public void AnchorEnd_Better_Than_Bottom_Equal_Inside_Window ()
  132. {
  133. var win = new Window ();
  134. var label = new Label ("This should be the last line.") {
  135. TextAlignment = TextAlignment.Centered,
  136. ColorScheme = Colors.Menu,
  137. Width = Dim.Fill (),
  138. X = Pos.Center (),
  139. Y = Pos.AnchorEnd (1)
  140. };
  141. win.Add (label);
  142. var top = Application.Top;
  143. top.Add (win);
  144. Application.Begin (top);
  145. ((FakeDriver)Application.Driver).SetBufferSize (40, 10);
  146. Assert.True (label.AutoSize);
  147. Assert.Equal (29, label.Text.Length);
  148. Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
  149. Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
  150. Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
  151. var expected = @"
  152. ┌──────────────────────────────────────┐
  153. │ │
  154. │ │
  155. │ │
  156. │ │
  157. │ │
  158. │ │
  159. │ │
  160. │ This should be the last line. │
  161. └──────────────────────────────────────┘
  162. ";
  163. TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  164. }
  165. [Fact]
  166. [AutoInitShutdown]
  167. public void Bottom_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
  168. {
  169. var win = new Window ();
  170. var label = new Label ("This should be the last line.") {
  171. TextAlignment = TextAlignment.Centered,
  172. ColorScheme = Colors.Menu,
  173. Width = Dim.Fill (),
  174. X = Pos.Center (),
  175. Y = Pos.Bottom (win) - 4 // two lines top and bottom borders more two lines above border
  176. };
  177. win.Add (label);
  178. var menu = new MenuBar (new MenuBarItem [] { new ("Menu", "", null) });
  179. var status = new StatusBar (new StatusItem [] { new (Key.F1, "~F1~ Help", null) });
  180. var top = Application.Top;
  181. top.Add (win, menu, status);
  182. Application.Begin (top);
  183. Assert.True (label.AutoSize);
  184. Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
  185. Assert.Equal (new Rect (0, 0, 80, 1), menu.Frame);
  186. Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
  187. Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
  188. Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
  189. var expected = @"
  190. Menu
  191. ┌──────────────────────────────────────────────────────────────────────────────┐
  192. │ │
  193. │ │
  194. │ │
  195. │ │
  196. │ │
  197. │ │
  198. │ │
  199. │ │
  200. │ │
  201. │ │
  202. │ │
  203. │ │
  204. │ │
  205. │ │
  206. │ │
  207. │ │
  208. │ │
  209. │ │
  210. │ │
  211. │ │
  212. │ This should be the last line. │
  213. └──────────────────────────────────────────────────────────────────────────────┘
  214. F1 Help
  215. ";
  216. TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  217. }
  218. [Fact]
  219. [AutoInitShutdown]
  220. public void AnchorEnd_Better_Than_Bottom_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
  221. {
  222. var win = new Window ();
  223. var label = new Label ("This should be the last line.") {
  224. TextAlignment = TextAlignment.Centered,
  225. ColorScheme = Colors.Menu,
  226. Width = Dim.Fill (),
  227. X = Pos.Center (),
  228. Y = Pos.AnchorEnd (1)
  229. };
  230. win.Add (label);
  231. var menu = new MenuBar (new MenuBarItem [] { new ("Menu", "", null) });
  232. var status = new StatusBar (new StatusItem [] { new (Key.F1, "~F1~ Help", null) });
  233. var top = Application.Top;
  234. top.Add (win, menu, status);
  235. Application.Begin (top);
  236. Assert.True (label.AutoSize);
  237. Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
  238. Assert.Equal (new Rect (0, 0, 80, 1), menu.Frame);
  239. Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
  240. Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
  241. Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
  242. var expected = @"
  243. Menu
  244. ┌──────────────────────────────────────────────────────────────────────────────┐
  245. │ │
  246. │ │
  247. │ │
  248. │ │
  249. │ │
  250. │ │
  251. │ │
  252. │ │
  253. │ │
  254. │ │
  255. │ │
  256. │ │
  257. │ │
  258. │ │
  259. │ │
  260. │ │
  261. │ │
  262. │ │
  263. │ │
  264. │ │
  265. │ This should be the last line. │
  266. └──────────────────────────────────────────────────────────────────────────────┘
  267. F1 Help
  268. ";
  269. TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  270. }
  271. [Fact]
  272. public void AnchorEnd_Negative_Throws ()
  273. {
  274. Pos pos;
  275. var n = -1;
  276. Assert.Throws<ArgumentException> (() => pos = Pos.AnchorEnd (n));
  277. }
  278. [Fact]
  279. public void At_SetsValue ()
  280. {
  281. var pos = Pos.At (0);
  282. Assert.Equal ("Absolute(0)", pos.ToString ());
  283. pos = Pos.At (5);
  284. Assert.Equal ("Absolute(5)", pos.ToString ());
  285. pos = Pos.At (-1);
  286. Assert.Equal ("Absolute(-1)", pos.ToString ());
  287. }
  288. [Fact]
  289. public void At_Equal ()
  290. {
  291. var n1 = 0;
  292. var n2 = 0;
  293. var pos1 = Pos.At (n1);
  294. var pos2 = Pos.At (n2);
  295. Assert.Equal (pos1, pos2);
  296. }
  297. [Fact]
  298. public void SetSide_Null_Throws ()
  299. {
  300. var pos = Pos.Left (null);
  301. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  302. pos = Pos.X (null);
  303. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  304. pos = Pos.Top (null);
  305. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  306. pos = Pos.Y (null);
  307. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  308. pos = Pos.Bottom (null);
  309. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  310. pos = Pos.Right (null);
  311. Assert.Throws<NullReferenceException> (() => pos.ToString ());
  312. }
  313. // TODO: Test Left, Top, Right bottom Equal
  314. /// <summary>
  315. /// Tests Pos.Left, Pos.X, Pos.Top, Pos.Y, Pos.Right, and Pos.Bottom set operations
  316. /// </summary>
  317. [Fact]
  318. public void PosSide_SetsValue ()
  319. {
  320. string side; // used in format string
  321. var testRect = Rect.Empty;
  322. var testInt = 0;
  323. Pos pos;
  324. // Pos.Left
  325. side = "x";
  326. testInt = 0;
  327. testRect = Rect.Empty;
  328. pos = Pos.Left (new View ());
  329. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  330. pos = Pos.Left (new View (testRect));
  331. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  332. testRect = new Rect (1, 2, 3, 4);
  333. pos = Pos.Left (new View (testRect));
  334. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  335. // Pos.Left(win) + 0
  336. pos = Pos.Left (new View (testRect)) + testInt;
  337. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  338. testInt = 1;
  339. // Pos.Left(win) +1
  340. pos = Pos.Left (new View (testRect)) + testInt;
  341. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  342. testInt = -1;
  343. // Pos.Left(win) -1
  344. pos = Pos.Left (new View (testRect)) - testInt;
  345. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  346. // Pos.X
  347. side = "x";
  348. testInt = 0;
  349. testRect = Rect.Empty;
  350. pos = Pos.X (new View ());
  351. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  352. pos = Pos.X (new View (testRect));
  353. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  354. testRect = new Rect (1, 2, 3, 4);
  355. pos = Pos.X (new View (testRect));
  356. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  357. // Pos.X(win) + 0
  358. pos = Pos.X (new View (testRect)) + testInt;
  359. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  360. testInt = 1;
  361. // Pos.X(win) +1
  362. pos = Pos.X (new View (testRect)) + testInt;
  363. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  364. testInt = -1;
  365. // Pos.X(win) -1
  366. pos = Pos.X (new View (testRect)) - testInt;
  367. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  368. // Pos.Top
  369. side = "y";
  370. testInt = 0;
  371. testRect = Rect.Empty;
  372. pos = Pos.Top (new View ());
  373. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  374. pos = Pos.Top (new View (testRect));
  375. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  376. testRect = new Rect (1, 2, 3, 4);
  377. pos = Pos.Top (new View (testRect));
  378. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  379. // Pos.Top(win) + 0
  380. pos = Pos.Top (new View (testRect)) + testInt;
  381. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  382. testInt = 1;
  383. // Pos.Top(win) +1
  384. pos = Pos.Top (new View (testRect)) + testInt;
  385. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  386. testInt = -1;
  387. // Pos.Top(win) -1
  388. pos = Pos.Top (new View (testRect)) - testInt;
  389. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  390. // Pos.Y
  391. side = "y";
  392. testInt = 0;
  393. testRect = Rect.Empty;
  394. pos = Pos.Y (new View ());
  395. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  396. pos = Pos.Y (new View (testRect));
  397. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  398. testRect = new Rect (1, 2, 3, 4);
  399. pos = Pos.Y (new View (testRect));
  400. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  401. // Pos.Y(win) + 0
  402. pos = Pos.Y (new View (testRect)) + testInt;
  403. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  404. testInt = 1;
  405. // Pos.Y(win) +1
  406. pos = Pos.Y (new View (testRect)) + testInt;
  407. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  408. testInt = -1;
  409. // Pos.Y(win) -1
  410. pos = Pos.Y (new View (testRect)) - testInt;
  411. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  412. // Pos.Bottom
  413. side = "bottom";
  414. testRect = Rect.Empty;
  415. testInt = 0;
  416. pos = Pos.Bottom (new View ());
  417. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  418. pos = Pos.Bottom (new View (testRect));
  419. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  420. testRect = new Rect (1, 2, 3, 4);
  421. pos = Pos.Bottom (new View (testRect));
  422. Assert.Equal ($"Combine(View({side},View()({testRect})){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  423. // Pos.Bottom(win) + 0
  424. pos = Pos.Bottom (new View (testRect)) + testInt;
  425. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  426. testInt = 1;
  427. // Pos.Bottom(win) +1
  428. pos = Pos.Bottom (new View (testRect)) + testInt;
  429. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  430. testInt = -1;
  431. // Pos.Bottom(win) -1
  432. pos = Pos.Bottom (new View (testRect)) - testInt;
  433. Assert.Equal ($"Combine(Combine(View({side},View()({testRect}))+Absolute(0)){(testInt < 0 ? '-' : '+')}Absolute({testInt}))", pos.ToString ());
  434. }
  435. // See: https://github.com/gui-cs/Terminal.Gui/issues/504
  436. [Fact]
  437. public void LeftTopBottomRight_Win_ShouldNotThrow ()
  438. {
  439. // Setup Fake driver
  440. (Window win, Button button) setup ()
  441. {
  442. Application.Init (new FakeDriver ());
  443. Application.Iteration = () => {
  444. Application.RequestStop ();
  445. };
  446. var win = new Window () {
  447. X = 0,
  448. Y = 0,
  449. Width = Dim.Fill (),
  450. Height = Dim.Fill (),
  451. };
  452. Application.Top.Add (win);
  453. var button = new Button ("button") {
  454. X = Pos.Center (),
  455. };
  456. win.Add (button);
  457. return (win, button);
  458. }
  459. Application.RunState rs;
  460. void cleanup (Application.RunState rs)
  461. {
  462. // Cleanup
  463. Application.End (rs);
  464. // Shutdown must be called to safely clean up Application if Init has been called
  465. Application.Shutdown ();
  466. }
  467. // Test cases:
  468. var app = setup ();
  469. app.button.Y = Pos.Left (app.win);
  470. rs = Application.Begin (Application.Top);
  471. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  472. Application.RunLoop (rs);
  473. cleanup (rs);
  474. app = setup ();
  475. app.button.Y = Pos.X (app.win);
  476. rs = Application.Begin (Application.Top);
  477. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  478. Application.RunLoop (rs);
  479. cleanup (rs);
  480. app = setup ();
  481. app.button.Y = Pos.Top (app.win);
  482. rs = Application.Begin (Application.Top);
  483. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  484. Application.RunLoop (rs);
  485. cleanup (rs);
  486. app = setup ();
  487. app.button.Y = Pos.Y (app.win);
  488. rs = Application.Begin (Application.Top);
  489. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  490. Application.RunLoop (rs);
  491. cleanup (rs);
  492. app = setup ();
  493. app.button.Y = Pos.Bottom (app.win);
  494. rs = Application.Begin (Application.Top);
  495. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  496. Application.RunLoop (rs);
  497. cleanup (rs);
  498. app = setup ();
  499. app.button.Y = Pos.Right (app.win);
  500. rs = Application.Begin (Application.Top);
  501. // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
  502. Application.RunLoop (rs);
  503. cleanup (rs);
  504. }
  505. [Fact]
  506. public void Center_SetsValue ()
  507. {
  508. var pos = Pos.Center ();
  509. Assert.Equal ("Center", pos.ToString ());
  510. }
  511. [Fact]
  512. public void Percent_SetsValue ()
  513. {
  514. float f = 0;
  515. var pos = Pos.Percent (f);
  516. Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
  517. f = 0.5F;
  518. pos = Pos.Percent (f);
  519. Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
  520. f = 100;
  521. pos = Pos.Percent (f);
  522. Assert.Equal ($"Factor({f / 100:0.###})", pos.ToString ());
  523. }
  524. [Fact]
  525. public void Percent_Equal ()
  526. {
  527. float n1 = 0;
  528. float n2 = 0;
  529. var pos1 = Pos.Percent (n1);
  530. var pos2 = Pos.Percent (n2);
  531. Assert.Equal (pos1, pos2);
  532. n1 = n2 = 1;
  533. pos1 = Pos.Percent (n1);
  534. pos2 = Pos.Percent (n2);
  535. Assert.Equal (pos1, pos2);
  536. n1 = n2 = 0.5f;
  537. pos1 = Pos.Percent (n1);
  538. pos2 = Pos.Percent (n2);
  539. Assert.Equal (pos1, pos2);
  540. n1 = n2 = 100f;
  541. pos1 = Pos.Percent (n1);
  542. pos2 = Pos.Percent (n2);
  543. Assert.Equal (pos1, pos2);
  544. n1 = 0;
  545. n2 = 1;
  546. pos1 = Pos.Percent (n1);
  547. pos2 = Pos.Percent (n2);
  548. Assert.NotEqual (pos1, pos2);
  549. n1 = 0.5f;
  550. n2 = 1.5f;
  551. pos1 = Pos.Percent (n1);
  552. pos2 = Pos.Percent (n2);
  553. Assert.NotEqual (pos1, pos2);
  554. }
  555. [Fact]
  556. public void Percent_ThrowsOnIvalid ()
  557. {
  558. var pos = Pos.Percent (0);
  559. Assert.Throws<ArgumentException> (() => pos = Pos.Percent (-1));
  560. Assert.Throws<ArgumentException> (() => pos = Pos.Percent (101));
  561. Assert.Throws<ArgumentException> (() => pos = Pos.Percent (100.0001F));
  562. Assert.Throws<ArgumentException> (() => pos = Pos.Percent (1000001));
  563. }
  564. [Fact]
  565. public void ForceValidatePosDim_True_Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
  566. {
  567. Application.Init (new FakeDriver ());
  568. var t = Application.Top;
  569. var w = new Window () {
  570. X = Pos.Left (t) + 2,
  571. Y = Pos.At (2)
  572. };
  573. var v = new View () {
  574. X = Pos.Center (),
  575. Y = Pos.Percent (10),
  576. ForceValidatePosDim = true
  577. };
  578. w.Add (v);
  579. t.Add (w);
  580. t.Ready += (s, e) => {
  581. Assert.Equal (2, w.X = 2);
  582. Assert.Equal (2, w.Y = 2);
  583. Assert.Throws<ArgumentException> (() => v.X = 2);
  584. Assert.Throws<ArgumentException> (() => v.Y = 2);
  585. };
  586. Application.Iteration += () => Application.RequestStop ();
  587. Application.Run ();
  588. Application.Shutdown ();
  589. }
  590. [Fact]
  591. public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
  592. {
  593. Application.Init (new FakeDriver ());
  594. var t = Application.Top;
  595. var w = new Window (new Rect (1, 2, 4, 5));
  596. t.Add (w);
  597. t.Ready += (s, e) => {
  598. Assert.Equal (2, w.X = 2);
  599. Assert.Equal (2, w.Y = 2);
  600. };
  601. Application.Iteration += () => Application.RequestStop ();
  602. Application.Run ();
  603. Application.Shutdown ();
  604. }
  605. [Fact]
  606. public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
  607. {
  608. Application.Init (new FakeDriver ());
  609. var t = Application.Top;
  610. var w = new Window () {
  611. X = Pos.Left (t) + 2,
  612. Y = Pos.At (2)
  613. };
  614. var v = new View () {
  615. X = Pos.Center (),
  616. Y = Pos.Percent (10)
  617. };
  618. w.Add (v);
  619. t.Add (w);
  620. t.Ready += (s, e) => {
  621. v.LayoutStyle = LayoutStyle.Absolute;
  622. Assert.Equal (2, v.X = 2);
  623. Assert.Equal (2, v.Y = 2);
  624. };
  625. Application.Iteration += () => Application.RequestStop ();
  626. Application.Run ();
  627. Application.Shutdown ();
  628. }
  629. // DONE: Test PosCombine
  630. // DONE: Test operators
  631. // BUGBUG: v2 - This test is bogus. v1 and references it's superview's (f) superview (w).
  632. //[Fact]
  633. //public void PosCombine_Do_Not_Throws ()
  634. //{
  635. // Application.Init (new FakeDriver ());
  636. // var w = new Window () {
  637. // X = Pos.Left (Application.Top) + 2,
  638. // Y = Pos.Top (Application.Top) + 2
  639. // };
  640. // var f = new FrameView ();
  641. // var v1 = new View () {
  642. // X = Pos.Left (w) + 2,
  643. // Y = Pos.Top (w) + 2
  644. // };
  645. // var v2 = new View () {
  646. // X = Pos.Left (v1) + 2,
  647. // Y = Pos.Top (v1) + 2
  648. // };
  649. // f.Add (v1, v2);
  650. // w.Add (f);
  651. // Application.Top.Add (w);
  652. // f.X = Pos.X (Application.Top) + Pos.X (v2) - Pos.X (v1);
  653. // f.Y = Pos.Y (Application.Top) + Pos.Y (v2) - Pos.Y (v1);
  654. // Application.Top.LayoutComplete += (s, e) => {
  655. // Assert.Equal (0, Application.Top.Frame.X);
  656. // Assert.Equal (0, Application.Top.Frame.Y);
  657. // Assert.Equal (2, w.Frame.X);
  658. // Assert.Equal (2, w.Frame.Y);
  659. // Assert.Equal (2, f.Frame.X);
  660. // Assert.Equal (2, f.Frame.Y);
  661. // Assert.Equal (4, v1.Frame.X);
  662. // Assert.Equal (4, v1.Frame.Y);
  663. // Assert.Equal (6, v2.Frame.X);
  664. // Assert.Equal (6, v2.Frame.Y);
  665. // };
  666. // Application.Iteration += () => Application.RequestStop ();
  667. // Application.Run ();
  668. // Application.Shutdown ();
  669. //}
  670. [Fact]
  671. public void PosCombine_Will_Throws ()
  672. {
  673. Application.Init (new FakeDriver ());
  674. var t = Application.Top;
  675. var w = new Window () {
  676. X = Pos.Left (t) + 2,
  677. Y = Pos.Top (t) + 2
  678. };
  679. var f = new FrameView ();
  680. var v1 = new View () {
  681. X = Pos.Left (w) + 2,
  682. Y = Pos.Top (w) + 2
  683. };
  684. var v2 = new View () {
  685. X = Pos.Left (v1) + 2,
  686. Y = Pos.Top (v1) + 2
  687. };
  688. f.Add (v1); // v2 not added
  689. w.Add (f);
  690. t.Add (w);
  691. f.X = Pos.X (v2) - Pos.X (v1);
  692. f.Y = Pos.Y (v2) - Pos.Y (v1);
  693. Assert.Throws<InvalidOperationException> (() => Application.Run ());
  694. Application.Shutdown ();
  695. }
  696. [Fact]
  697. public void Pos_Add_Operator ()
  698. {
  699. Application.Init (new FakeDriver ());
  700. var top = Application.Top;
  701. var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
  702. var field = new TextField () { X = 0, Y = 0, Width = 20 };
  703. var count = 0;
  704. field.KeyDown += (s, k) => {
  705. if (k.KeyEvent.Key == Key.Enter) {
  706. field.Text = $"Label {count}";
  707. var label = new Label (field.Text) { X = 0, Y = field.Y, Width = 20 };
  708. view.Add (label);
  709. Assert.Equal ($"Label {count}", label.Text);
  710. Assert.Equal ($"Absolute({count})", label.Y.ToString ());
  711. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  712. field.Y += 1;
  713. count++;
  714. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  715. }
  716. };
  717. Application.Iteration += () => {
  718. while (count < 20) field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
  719. Application.RequestStop ();
  720. };
  721. var win = new Window ();
  722. win.Add (view);
  723. win.Add (field);
  724. top.Add (win);
  725. Application.Run (top);
  726. Assert.Equal (20, count);
  727. // Shutdown must be called to safely clean up Application if Init has been called
  728. Application.Shutdown ();
  729. }
  730. [Fact]
  731. public void Pos_Subtract_Operator ()
  732. {
  733. Application.Init (new FakeDriver ());
  734. var top = Application.Top;
  735. var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
  736. var field = new TextField () { X = 0, Y = 0, Width = 20 };
  737. var count = 20;
  738. var listLabels = new List<Label> ();
  739. for (int i = 0; i < count; i++) {
  740. field.Text = $"Label {i}";
  741. var label = new Label (field.Text) { X = 0, Y = field.Y, Width = 20 };
  742. view.Add (label);
  743. Assert.Equal ($"Label {i}", label.Text);
  744. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  745. listLabels.Add (label);
  746. Assert.Equal ($"Absolute({i})", field.Y.ToString ());
  747. field.Y += 1;
  748. Assert.Equal ($"Absolute({i + 1})", field.Y.ToString ());
  749. }
  750. field.KeyDown += (s, k) => {
  751. if (k.KeyEvent.Key == Key.Enter) {
  752. Assert.Equal ($"Label {count - 1}", listLabels [count - 1].Text);
  753. view.Remove (listLabels [count - 1]);
  754. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  755. field.Y -= 1;
  756. count--;
  757. Assert.Equal ($"Absolute({count})", field.Y.ToString ());
  758. }
  759. };
  760. Application.Iteration += () => {
  761. while (count > 0) field.OnKeyDown (new KeyEvent (Key.Enter, new KeyModifiers ()));
  762. Application.RequestStop ();
  763. };
  764. var win = new Window ();
  765. win.Add (view);
  766. win.Add (field);
  767. top.Add (win);
  768. Application.Run (top);
  769. Assert.Equal (0, count);
  770. // Shutdown must be called to safely clean up Application if Init has been called
  771. Application.Shutdown ();
  772. }
  773. [Fact]
  774. public void Internal_Tests ()
  775. {
  776. var posFactor = new Pos.PosFactor (0.10F);
  777. Assert.Equal (10, posFactor.Anchor (100));
  778. var posAnchorEnd = new Pos.PosAnchorEnd (1);
  779. Assert.Equal (99, posAnchorEnd.Anchor (100));
  780. var posCenter = new Pos.PosCenter ();
  781. Assert.Equal (50, posCenter.Anchor (100));
  782. var posAbsolute = new Pos.PosAbsolute (10);
  783. Assert.Equal (10, posAbsolute.Anchor (0));
  784. var posCombine = new Pos.PosCombine (true, posFactor, posAbsolute);
  785. Assert.Equal (posCombine.left, posFactor);
  786. Assert.Equal (posCombine.right, posAbsolute);
  787. Assert.Equal (20, posCombine.Anchor (100));
  788. posCombine = new Pos.PosCombine (true, posAbsolute, posFactor);
  789. Assert.Equal (posCombine.left, posAbsolute);
  790. Assert.Equal (posCombine.right, posFactor);
  791. Assert.Equal (20, posCombine.Anchor (100));
  792. var view = new View (new Rect (20, 10, 20, 1));
  793. var posViewX = new Pos.PosView (view, 0);
  794. Assert.Equal (20, posViewX.Anchor (0));
  795. var posViewY = new Pos.PosView (view, 1);
  796. Assert.Equal (10, posViewY.Anchor (0));
  797. var posRight = new Pos.PosView (view, 2);
  798. Assert.Equal (40, posRight.Anchor (0));
  799. var posViewBottom = new Pos.PosView (view, 3);
  800. Assert.Equal (11, posViewBottom.Anchor (0));
  801. }
  802. [Fact]
  803. public void Function_SetsValue ()
  804. {
  805. var text = "Test";
  806. var pos = Pos.Function (() => text.Length);
  807. Assert.Equal ("PosFunc(4)", pos.ToString ());
  808. text = "New Test";
  809. Assert.Equal ("PosFunc(8)", pos.ToString ());
  810. text = "";
  811. Assert.Equal ("PosFunc(0)", pos.ToString ());
  812. }
  813. [Fact]
  814. public void Function_Equal ()
  815. {
  816. var f1 = () => 0;
  817. var f2 = () => 0;
  818. var pos1 = Pos.Function (f1);
  819. var pos2 = Pos.Function (f2);
  820. Assert.Equal (pos1, pos2);
  821. f2 = () => 1;
  822. pos2 = Pos.Function (f2);
  823. Assert.NotEqual (pos1, pos2);
  824. }
  825. [Theory, AutoInitShutdown]
  826. [InlineData (true)]
  827. [InlineData (false)]
  828. public void PosPercentPlusOne (bool testHorizontal)
  829. {
  830. var container = new View {
  831. Width = 100,
  832. Height = 100,
  833. };
  834. var label = new Label {
  835. X = testHorizontal ? Pos.Percent (50) + Pos.Percent (10) + 1 : 1,
  836. Y = testHorizontal ? 1 : Pos.Percent (50) + Pos.Percent (10) + 1,
  837. Width = 10,
  838. Height = 10,
  839. };
  840. container.Add (label);
  841. Application.Top.Add (container);
  842. Application.Top.LayoutSubviews ();
  843. Assert.Equal (100, container.Frame.Width);
  844. Assert.Equal (100, container.Frame.Height);
  845. if (testHorizontal) {
  846. Assert.Equal (61, label.Frame.X);
  847. Assert.Equal (1, label.Frame.Y);
  848. } else {
  849. Assert.Equal (1, label.Frame.X);
  850. Assert.Equal (61, label.Frame.Y);
  851. }
  852. }
  853. [Fact]
  854. public void PosCombine_Referencing_Same_View ()
  855. {
  856. var super = new View ("super") {
  857. Width = 10,
  858. Height = 10
  859. };
  860. var view1 = new View ("view1") {
  861. Width = 2,
  862. Height = 2,
  863. };
  864. var view2 = new View ("view2") {
  865. Width = 2,
  866. Height = 2,
  867. };
  868. view2.X = Pos.AnchorEnd () - (Pos.Right (view2) - Pos.Left (view2));
  869. super.Add (view1, view2);
  870. super.BeginInit ();
  871. super.EndInit ();
  872. var exception = Record.Exception (super.LayoutSubviews);
  873. Assert.Null (exception);
  874. Assert.Equal (new Rect (0, 0, 10, 10), super.Frame);
  875. Assert.Equal (new Rect (0, 0, 2, 2), view1.Frame);
  876. Assert.Equal (new Rect (8, 0, 2, 2), view2.Frame);
  877. }
  878. }
  879. }