PosTests.cs 33 KB

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