DimAutoTests.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. using System.Globalization;
  2. using System.Text;
  3. using Xunit.Abstractions;
  4. // Alias Console to MockConsole so we don't accidentally use Console
  5. using Console = Terminal.Gui.FakeConsole;
  6. namespace Terminal.Gui.ViewTests;
  7. public class DimAutoTests
  8. {
  9. private readonly ITestOutputHelper _output;
  10. public DimAutoTests (ITestOutputHelper output)
  11. {
  12. _output = output;
  13. Console.OutputEncoding = Encoding.Default;
  14. // Change current culture
  15. var culture = CultureInfo.CreateSpecificCulture ("en-US");
  16. Thread.CurrentThread.CurrentCulture = culture;
  17. Thread.CurrentThread.CurrentUICulture = culture;
  18. }
  19. // Test min - ensure that if min is specified in the DimAuto constructor it is honored
  20. [Fact]
  21. public void DimAuto_Min ()
  22. {
  23. var superView = new View
  24. {
  25. X = 0,
  26. Y = 0,
  27. Width = Dim.Auto (min: 10),
  28. Height = Dim.Auto (min: 10),
  29. ValidatePosDim = true
  30. };
  31. var subView = new View
  32. {
  33. X = 0,
  34. Y = 0,
  35. Width = 5,
  36. Height = 5
  37. };
  38. superView.Add (subView);
  39. superView.BeginInit ();
  40. superView.EndInit ();
  41. superView.SetRelativeLayout (new (10, 10));
  42. superView.LayoutSubviews (); // no throw
  43. Assert.Equal (10, superView.Frame.Width);
  44. Assert.Equal (10, superView.Frame.Height);
  45. }
  46. // what happens if DimAuto (min: 10) and the subview moves to a negative coord?
  47. [Fact]
  48. public void DimAuto_Min_Resets_If_Subview_Moves_Negative ()
  49. {
  50. var superView = new View
  51. {
  52. X = 0,
  53. Y = 0,
  54. Width = Dim.Auto (min: 10),
  55. Height = Dim.Auto (min: 10),
  56. ValidatePosDim = true
  57. };
  58. var subView = new View
  59. {
  60. X = 0,
  61. Y = 0,
  62. Width = 5,
  63. Height = 5
  64. };
  65. superView.Add (subView);
  66. superView.BeginInit ();
  67. superView.EndInit ();
  68. superView.SetRelativeLayout (new ( 10, 10));
  69. superView.LayoutSubviews (); // no throw
  70. Assert.Equal (10, superView.Frame.Width);
  71. Assert.Equal (10, superView.Frame.Height);
  72. subView.X = -1;
  73. subView.Y = -1;
  74. superView.SetRelativeLayout (new ( 10, 10));
  75. superView.LayoutSubviews (); // no throw
  76. Assert.Equal (5, subView.Frame.Width);
  77. Assert.Equal (5, subView.Frame.Height);
  78. Assert.Equal (10, superView.Frame.Width);
  79. Assert.Equal (10, superView.Frame.Height);
  80. }
  81. [Fact]
  82. public void DimAuto_Min_Resets_If_Subview_Shrinks ()
  83. {
  84. var superView = new View
  85. {
  86. X = 0,
  87. Y = 0,
  88. Width = Dim.Auto (min: 10),
  89. Height = Dim.Auto (min: 10),
  90. ValidatePosDim = true
  91. };
  92. var subView = new View
  93. {
  94. X = 0,
  95. Y = 0,
  96. Width = 5,
  97. Height = 5
  98. };
  99. superView.Add (subView);
  100. superView.BeginInit ();
  101. superView.EndInit ();
  102. superView.SetRelativeLayout (new ( 10, 10));
  103. superView.LayoutSubviews (); // no throw
  104. Assert.Equal (10, superView.Frame.Width);
  105. Assert.Equal (10, superView.Frame.Height);
  106. subView.Width = 3;
  107. subView.Height = 3;
  108. superView.SetRelativeLayout (new ( 10, 10));
  109. superView.LayoutSubviews (); // no throw
  110. Assert.Equal (3, subView.Frame.Width);
  111. Assert.Equal (3, subView.Frame.Height);
  112. Assert.Equal (10, superView.Frame.Width);
  113. Assert.Equal (10, superView.Frame.Height);
  114. }
  115. [Theory]
  116. [InlineData (0, 0, 0, 0, 0)]
  117. [InlineData (0, 0, 5, 0, 0)]
  118. [InlineData (0, 0, 0, 5, 5)]
  119. [InlineData (0, 0, 5, 5, 5)]
  120. [InlineData (1, 0, 5, 0, 0)]
  121. [InlineData (1, 0, 0, 5, 5)]
  122. [InlineData (1, 0, 5, 5, 5)]
  123. [InlineData (1, 1, 5, 5, 6)]
  124. [InlineData (-1, 0, 5, 0, 0)]
  125. [InlineData (-1, 0, 0, 5, 5)]
  126. [InlineData (-1, 0, 5, 5, 5)]
  127. [InlineData (-1, -1, 5, 5, 4)]
  128. public void Height_Auto_Width_NotChanged (int subX, int subY, int subWidth, int subHeight, int expectedHeight)
  129. {
  130. var superView = new View
  131. {
  132. X = 0,
  133. Y = 0,
  134. Width = 10,
  135. Height = Dim.Auto (),
  136. ValidatePosDim = true
  137. };
  138. var subView = new View
  139. {
  140. X = subX,
  141. Y = subY,
  142. Width = subWidth,
  143. Height = subHeight,
  144. ValidatePosDim = true
  145. };
  146. superView.Add (subView);
  147. superView.BeginInit ();
  148. superView.EndInit ();
  149. superView.SetRelativeLayout (new ( 10, 10));
  150. Assert.Equal (new Rectangle (0, 0, 10, expectedHeight), superView.Frame);
  151. }
  152. [Fact]
  153. public void NoSubViews_Does_Nothing ()
  154. {
  155. var superView = new View
  156. {
  157. X = 0,
  158. Y = 0,
  159. Width = Dim.Auto (),
  160. Height = Dim.Auto (),
  161. ValidatePosDim = true
  162. };
  163. superView.BeginInit ();
  164. superView.EndInit ();
  165. superView.SetRelativeLayout (new ( 10, 10));
  166. Assert.Equal (new Rectangle (0, 0, 0, 0), superView.Frame);
  167. superView.SetRelativeLayout (new ( 10, 10));
  168. Assert.Equal (new Rectangle (0, 0, 0, 0), superView.Frame);
  169. }
  170. [Theory]
  171. [InlineData (0, 0, 0, 0, 0, 0)]
  172. [InlineData (0, 0, 5, 0, 5, 0)]
  173. [InlineData (0, 0, 0, 5, 0, 5)]
  174. [InlineData (0, 0, 5, 5, 5, 5)]
  175. [InlineData (1, 0, 5, 0, 6, 0)]
  176. [InlineData (1, 0, 0, 5, 1, 5)]
  177. [InlineData (1, 0, 5, 5, 6, 5)]
  178. [InlineData (1, 1, 5, 5, 6, 6)]
  179. [InlineData (-1, 0, 5, 0, 4, 0)]
  180. [InlineData (-1, 0, 0, 5, 0, 5)]
  181. [InlineData (-1, 0, 5, 5, 4, 5)]
  182. [InlineData (-1, -1, 5, 5, 4, 4)]
  183. public void SubView_ChangesSuperViewSize (int subX, int subY, int subWidth, int subHeight, int expectedWidth, int expectedHeight)
  184. {
  185. var superView = new View
  186. {
  187. X = 0,
  188. Y = 0,
  189. Width = Dim.Auto (),
  190. Height = Dim.Auto (),
  191. ValidatePosDim = true
  192. };
  193. var subView = new View
  194. {
  195. X = subX,
  196. Y = subY,
  197. Width = subWidth,
  198. Height = subHeight,
  199. ValidatePosDim = true
  200. };
  201. superView.Add (subView);
  202. superView.BeginInit ();
  203. superView.EndInit ();
  204. superView.SetRelativeLayout (new ( 10, 10));
  205. Assert.Equal (new Rectangle (0, 0, expectedWidth, expectedHeight), superView.Frame);
  206. }
  207. // Test validation
  208. [Fact]
  209. public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Dims ()
  210. {
  211. var superView = new View
  212. {
  213. X = 0,
  214. Y = 0,
  215. Width = Dim.Auto (),
  216. Height = Dim.Auto (),
  217. ValidatePosDim = true
  218. };
  219. var subView = new View
  220. {
  221. X = 0,
  222. Y = 0,
  223. Width = Dim.Fill (),
  224. Height = 10,
  225. ValidatePosDim = true
  226. };
  227. superView.BeginInit ();
  228. superView.EndInit ();
  229. Assert.Throws<InvalidOperationException> (() => superView.Add (subView));
  230. subView.Width = 10;
  231. superView.Add (subView);
  232. superView.SetRelativeLayout (new ( 10, 10));
  233. superView.LayoutSubviews (); // no throw
  234. subView.Width = Dim.Fill ();
  235. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  236. subView.Width = 10;
  237. subView.Height = Dim.Fill ();
  238. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  239. subView.Height = 10;
  240. subView.Height = Dim.Percent (50);
  241. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  242. subView.Height = 10;
  243. subView.X = Pos.Center ();
  244. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  245. subView.X = 0;
  246. subView.Y = Pos.Center ();
  247. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  248. subView.Y = 0;
  249. subView.Width = 10;
  250. subView.Height = 10;
  251. subView.X = 0;
  252. subView.Y = 0;
  253. superView.SetRelativeLayout (new ( 0, 0));
  254. superView.LayoutSubviews ();
  255. }
  256. // Test validation
  257. [Fact]
  258. public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Dims_Combine ()
  259. {
  260. var superView = new View
  261. {
  262. X = 0,
  263. Y = 0,
  264. Width = Dim.Auto (),
  265. Height = Dim.Auto (),
  266. ValidatePosDim = true
  267. };
  268. var subView = new View
  269. {
  270. X = 0,
  271. Y = 0,
  272. Width = 10,
  273. Height = 10
  274. };
  275. var subView2 = new View
  276. {
  277. X = 0,
  278. Y = 0,
  279. Width = 10,
  280. Height = 10
  281. };
  282. superView.Add (subView, subView2);
  283. superView.BeginInit ();
  284. superView.EndInit ();
  285. superView.SetRelativeLayout (new ( 0, 0));
  286. superView.LayoutSubviews (); // no throw
  287. subView.Height = Dim.Fill () + 3;
  288. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  289. subView.Height = 0;
  290. subView.Height = 3 + Dim.Fill ();
  291. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  292. subView.Height = 0;
  293. subView.Height = 3 + 5 + Dim.Fill ();
  294. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  295. subView.Height = 0;
  296. subView.Height = 3 + 5 + Dim.Percent (10);
  297. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  298. subView.Height = 0;
  299. // Tests nested Combine
  300. subView.Height = 5 + new Dim.DimCombine (true, 3, new Dim.DimCombine (true, Dim.Percent (10), 9));
  301. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  302. }
  303. [Fact]
  304. public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Pos_Combine ()
  305. {
  306. var superView = new View
  307. {
  308. X = 0,
  309. Y = 0,
  310. Width = Dim.Auto (),
  311. Height = Dim.Auto (),
  312. ValidatePosDim = true
  313. };
  314. var subView = new View
  315. {
  316. X = 0,
  317. Y = 0,
  318. Width = 10,
  319. Height = 10
  320. };
  321. var subView2 = new View
  322. {
  323. X = 0,
  324. Y = 0,
  325. Width = 10,
  326. Height = 10
  327. };
  328. superView.Add (subView, subView2);
  329. superView.BeginInit ();
  330. superView.EndInit ();
  331. superView.SetRelativeLayout (new ( 0, 0));
  332. superView.LayoutSubviews (); // no throw
  333. subView.X = Pos.Right (subView2);
  334. superView.SetRelativeLayout (new ( 0, 0));
  335. superView.LayoutSubviews (); // no throw
  336. subView.X = Pos.Right (subView2) + 3;
  337. superView.SetRelativeLayout (new ( 0, 0)); // no throw
  338. superView.LayoutSubviews (); // no throw
  339. subView.X = new Pos.PosCombine (true, Pos.Right (subView2), new Pos.PosCombine (true, 7, 9));
  340. superView.SetRelativeLayout (new ( 0, 0)); // no throw
  341. subView.X = Pos.Center () + 3;
  342. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  343. subView.X = 0;
  344. subView.X = 3 + Pos.Center ();
  345. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  346. subView.X = 0;
  347. subView.X = 3 + 5 + Pos.Center ();
  348. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  349. subView.X = 0;
  350. subView.X = 3 + 5 + Pos.Percent (10);
  351. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  352. subView.X = 0;
  353. subView.X = Pos.Percent (10) + Pos.Center ();
  354. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  355. subView.X = 0;
  356. // Tests nested Combine
  357. subView.X = 5 + new Pos.PosCombine (true, Pos.Right (subView2), new Pos.PosCombine (true, Pos.Center (), 9));
  358. Assert.Throws<InvalidOperationException> (() => superView.SetRelativeLayout (new ( 0, 0)));
  359. subView.X = 0;
  360. }
  361. [Theory]
  362. [InlineData (0, 0, 0, 0, 0)]
  363. [InlineData (0, 0, 5, 0, 5)]
  364. [InlineData (0, 0, 0, 5, 0)]
  365. [InlineData (0, 0, 5, 5, 5)]
  366. [InlineData (1, 0, 5, 0, 6)]
  367. [InlineData (1, 0, 0, 5, 1)]
  368. [InlineData (1, 0, 5, 5, 6)]
  369. [InlineData (1, 1, 5, 5, 6)]
  370. [InlineData (-1, 0, 5, 0, 4)]
  371. [InlineData (-1, 0, 0, 5, 0)]
  372. [InlineData (-1, 0, 5, 5, 4)]
  373. [InlineData (-1, -1, 5, 5, 4)]
  374. public void Width_Auto_Height_NotChanged (int subX, int subY, int subWidth, int subHeight, int expectedWidth)
  375. {
  376. var superView = new View
  377. {
  378. X = 0,
  379. Y = 0,
  380. Width = Dim.Auto (),
  381. Height = 10,
  382. ValidatePosDim = true
  383. };
  384. var subView = new View
  385. {
  386. X = subX,
  387. Y = subY,
  388. Width = subWidth,
  389. Height = subHeight,
  390. ValidatePosDim = true
  391. };
  392. superView.Add (subView);
  393. superView.BeginInit ();
  394. superView.EndInit ();
  395. superView.SetRelativeLayout (new ( 10, 10));
  396. Assert.Equal (new Rectangle (0, 0, expectedWidth, 10), superView.Frame);
  397. }
  398. // Test that when a view has Width set to DimAuto (min: x) the width is never < x even if SetRelativeLayout is called with smaller bounds
  399. [Theory]
  400. [InlineData (0, 0)]
  401. [InlineData (1, 1)]
  402. [InlineData (3, 3)]
  403. [InlineData (4, 4)]
  404. [InlineData (5, 4)] // This is clearly invalid, but we choose to not throw but log a debug message
  405. public void Width_Auto_Min (int min, int expectedWidth)
  406. {
  407. var superView = new View
  408. {
  409. X = 0,
  410. Y = 0,
  411. Width = Dim.Auto (min: min),
  412. Height = 1,
  413. ValidatePosDim = true
  414. };
  415. superView.BeginInit ();
  416. superView.EndInit ();
  417. superView.SetRelativeLayout (new ( 4, 1));
  418. Assert.Equal (expectedWidth, superView.Frame.Width);
  419. }
  420. // Test Dim.Fill - Fill should not impact width of the DimAuto superview
  421. [Theory]
  422. [InlineData (0, 0, 0, 10, 10)]
  423. [InlineData (0, 1, 0, 10, 10)]
  424. [InlineData (0, 11, 0, 10, 10)]
  425. [InlineData (0, 10, 0, 10, 10)]
  426. [InlineData (0, 5, 0, 10, 10)]
  427. [InlineData (1, 5, 0, 10, 9)]
  428. [InlineData (1, 10, 0, 10, 9)]
  429. [InlineData (0, 0, 1, 10, 9)]
  430. [InlineData (0, 10, 1, 10, 9)]
  431. [InlineData (0, 5, 1, 10, 9)]
  432. [InlineData (1, 5, 1, 10, 8)]
  433. [InlineData (1, 10, 1, 10, 8)]
  434. public void Width_Fill_Fills (int subX, int superMinWidth, int fill, int expectedSuperWidth, int expectedSubWidth)
  435. {
  436. var superView = new View
  437. {
  438. X = 0,
  439. Y = 0,
  440. Width = Dim.Auto (min:superMinWidth),
  441. Height = 1,
  442. ValidatePosDim = true
  443. };
  444. var subView = new View
  445. {
  446. X = subX,
  447. Y = 0,
  448. Width = Dim.Fill (fill),
  449. Height = 1,
  450. ValidatePosDim = true
  451. };
  452. superView.Add (subView);
  453. superView.BeginInit ();
  454. superView.EndInit ();
  455. superView.SetRelativeLayout (new ( 10, 1));
  456. Assert.Equal (expectedSuperWidth, superView.Frame.Width);
  457. superView.LayoutSubviews ();
  458. Assert.Equal (expectedSubWidth, subView.Frame.Width);
  459. Assert.Equal (expectedSuperWidth, superView.Frame.Width);
  460. }
  461. // Test variations of Frame
  462. }