PosTests.cs 34 KB

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