ViewTests.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
  1. using System.ComponentModel;
  2. using System.Text;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewTests;
  5. public class ViewTests (ITestOutputHelper output)
  6. {
  7. // Generic lifetime (IDisposable) tests
  8. [Fact]
  9. [TestRespondersDisposed]
  10. public void Dispose_Works ()
  11. {
  12. var r = new View ();
  13. #if DEBUG_IDISPOSABL
  14. Assert.Equals (3, View.Instances.Count);
  15. #endif
  16. r.Dispose ();
  17. #if DEBUG_IDISPOSABLE
  18. Assert.Empty (View.Instances);
  19. #endif
  20. }
  21. [Fact]
  22. public void Disposing_Event_Notify_All_Subscribers_On_The_First_Container ()
  23. {
  24. #if DEBUG_IDISPOSABLE
  25. // Only clear before because need to test after assert
  26. View.Instances.Clear ();
  27. #endif
  28. var container1 = new View { Id = "Container1" };
  29. var count = 0;
  30. var view = new View { Id = "View" };
  31. view.Disposing += View_Disposing;
  32. container1.Add (view);
  33. Assert.Equal (container1, view.SuperView);
  34. void View_Disposing (object sender, EventArgs e)
  35. {
  36. count++;
  37. Assert.Equal (view, sender);
  38. container1.Remove ((View)sender);
  39. }
  40. Assert.Single (container1.Subviews);
  41. var container2 = new View { Id = "Container2" };
  42. container2.Add (view);
  43. Assert.Equal (container2, view.SuperView);
  44. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  45. container2.Dispose ();
  46. Assert.Empty (container1.Subviews);
  47. Assert.Empty (container2.Subviews);
  48. Assert.Equal (1, count);
  49. Assert.Null (view.SuperView);
  50. container1.Dispose ();
  51. #if DEBUG_IDISPOSABLE
  52. Assert.Empty (View.Instances);
  53. #endif
  54. }
  55. [Fact]
  56. public void Disposing_Event_Notify_All_Subscribers_On_The_Second_Container ()
  57. {
  58. #if DEBUG_IDISPOSABLE
  59. // Only clear before because need to test after assert
  60. View.Instances.Clear ();
  61. #endif
  62. var container1 = new View { Id = "Container1" };
  63. var view = new View { Id = "View" };
  64. container1.Add (view);
  65. Assert.Equal (container1, view.SuperView);
  66. Assert.Single (container1.Subviews);
  67. var container2 = new View { Id = "Container2" };
  68. var count = 0;
  69. view.Disposing += View_Disposing;
  70. container2.Add (view);
  71. Assert.Equal (container2, view.SuperView);
  72. void View_Disposing (object sender, EventArgs e)
  73. {
  74. count++;
  75. Assert.Equal (view, sender);
  76. container2.Remove ((View)sender);
  77. }
  78. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  79. container1.Dispose ();
  80. Assert.Empty (container1.Subviews);
  81. Assert.Empty (container2.Subviews);
  82. Assert.Equal (1, count);
  83. Assert.Null (view.SuperView);
  84. container2.Dispose ();
  85. #if DEBUG_IDISPOSABLE
  86. Assert.Empty (View.Instances);
  87. #endif
  88. }
  89. [Fact]
  90. public void Not_Notifying_Dispose ()
  91. {
  92. // Only clear before because need to test after assert
  93. #if DEBUG_IDISPOSABLE
  94. View.Instances.Clear ();
  95. #endif
  96. var container1 = new View { Id = "Container1" };
  97. var view = new View { Id = "View" };
  98. container1.Add (view);
  99. Assert.Equal (container1, view.SuperView);
  100. Assert.Single (container1.Subviews);
  101. var container2 = new View { Id = "Container2" };
  102. container2.Add (view);
  103. Assert.Equal (container2, view.SuperView);
  104. Assert.Equal (container1.Subviews.Count, container2.Subviews.Count);
  105. container1.Dispose ();
  106. Assert.Empty (container1.Subviews);
  107. Assert.NotEmpty (container2.Subviews);
  108. Assert.Single (container2.Subviews);
  109. Assert.Null (view.SuperView);
  110. // Trying access disposed properties
  111. #if DEBUG_IDISPOSABLE
  112. Assert.True (container2.Subviews [0].WasDisposed);
  113. #endif
  114. Assert.False (container2.Subviews [0].CanFocus);
  115. Assert.Null (container2.Subviews [0].Margin);
  116. Assert.Null (container2.Subviews [0].Border);
  117. Assert.Null (container2.Subviews [0].Padding);
  118. Assert.Null (view.SuperView);
  119. container2.Dispose ();
  120. #if DEBUG_IDISPOSABLE
  121. Assert.Empty (View.Instances);
  122. #endif
  123. }
  124. [Fact]
  125. [AutoInitShutdown]
  126. public void Clear_Viewport_Can_Use_Driver_AddRune_Or_AddStr_Methods ()
  127. {
  128. var view = new FrameView { Width = Dim.Fill (), Height = Dim.Fill () };
  129. view.DrawingContent += (s, e) =>
  130. {
  131. Region savedClip = view.ClipViewport ();
  132. for (var row = 0; row < view.Viewport.Height; row++)
  133. {
  134. Application.Driver?.Move (1, row + 1);
  135. for (var col = 0; col < view.Viewport.Width; col++)
  136. {
  137. Application.Driver?.AddStr ($"{col}");
  138. }
  139. }
  140. View.SetClip (savedClip);
  141. e.Cancel = true;
  142. };
  143. var top = new Toplevel ();
  144. top.Add (view);
  145. Application.Begin (top);
  146. ((FakeDriver)Application.Driver!).SetBufferSize (20, 10);
  147. var expected = @"
  148. ┌──────────────────┐
  149. │012345678910111213│
  150. │012345678910111213│
  151. │012345678910111213│
  152. │012345678910111213│
  153. │012345678910111213│
  154. │012345678910111213│
  155. │012345678910111213│
  156. │012345678910111213│
  157. └──────────────────┘
  158. ";
  159. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  160. Assert.Equal (new (0, 0, 20, 10), pos);
  161. view.FillRect (view.Viewport);
  162. expected = @"
  163. ┌──────────────────┐
  164. │ │
  165. │ │
  166. │ │
  167. │ │
  168. │ │
  169. │ │
  170. │ │
  171. │ │
  172. └──────────────────┘
  173. ";
  174. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  175. top.Dispose ();
  176. }
  177. [Fact]
  178. [AutoInitShutdown]
  179. public void Clear_Can_Use_Driver_AddRune_Or_AddStr_Methods ()
  180. {
  181. var view = new FrameView { Width = Dim.Fill (), Height = Dim.Fill () };
  182. view.DrawingContent += (s, e) =>
  183. {
  184. Region savedClip = view.ClipViewport ();
  185. for (var row = 0; row < view.Viewport.Height; row++)
  186. {
  187. Application.Driver?.Move (1, row + 1);
  188. for (var col = 0; col < view.Viewport.Width; col++)
  189. {
  190. Application.Driver?.AddStr ($"{col}");
  191. }
  192. }
  193. View.SetClip (savedClip);
  194. e.Cancel = true;
  195. };
  196. var top = new Toplevel ();
  197. top.Add (view);
  198. Application.Begin (top);
  199. ((FakeDriver)Application.Driver!).SetBufferSize (20, 10);
  200. var expected = @"
  201. ┌──────────────────┐
  202. │012345678910111213│
  203. │012345678910111213│
  204. │012345678910111213│
  205. │012345678910111213│
  206. │012345678910111213│
  207. │012345678910111213│
  208. │012345678910111213│
  209. │012345678910111213│
  210. └──────────────────┘
  211. ";
  212. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  213. Assert.Equal (new (0, 0, 20, 10), pos);
  214. view.FillRect (view.Viewport);
  215. expected = @"
  216. ┌──────────────────┐
  217. │ │
  218. │ │
  219. │ │
  220. │ │
  221. │ │
  222. │ │
  223. │ │
  224. │ │
  225. └──────────────────┘
  226. ";
  227. pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
  228. top.Dispose ();
  229. }
  230. [Theory]
  231. [AutoInitShutdown (configLocation: ConfigurationManager.ConfigLocations.DefaultOnly)]
  232. [InlineData (true)]
  233. [InlineData (false)]
  234. public void Clear_Does_Not_Spillover_Its_Parent (bool label)
  235. {
  236. var root = new View { Width = 20, Height = 10, ColorScheme = Colors.ColorSchemes ["Base"] };
  237. string text = new ('c', 100);
  238. View v = label
  239. // Label has Width/Height == AutoSize, so Frame.Size will be (100, 1)
  240. ? new Label { Text = text }
  241. // TextView has Width/Height == (Dim.Fill, 1), so Frame.Size will be 20 (width of root), 1
  242. : new TextView { Width = Dim.Fill (), Height = 1, Text = text };
  243. root.Add (v);
  244. var top = new Toplevel ();
  245. top.Add (root);
  246. RunState runState = Application.Begin (top);
  247. Application.RunIteration (ref runState);
  248. if (label)
  249. {
  250. Assert.False (v.CanFocus);
  251. Assert.Equal (new (0, 0, text.Length, 1), v.Frame);
  252. }
  253. else
  254. {
  255. Assert.True (v.CanFocus);
  256. Assert.Equal (new (0, 0, 20, 1), v.Frame);
  257. }
  258. TestHelpers.AssertDriverContentsWithFrameAre (
  259. @"
  260. cccccccccccccccccccc",
  261. output
  262. );
  263. Attribute [] attributes =
  264. {
  265. Colors.ColorSchemes ["TopLevel"].Normal,
  266. Colors.ColorSchemes ["Base"].Normal,
  267. Colors.ColorSchemes ["Base"].Focus
  268. };
  269. if (label)
  270. {
  271. TestHelpers.AssertDriverAttributesAre (
  272. @"
  273. 111111111111111111110
  274. 111111111111111111110",
  275. output,
  276. Application.Driver,
  277. attributes
  278. );
  279. }
  280. else
  281. {
  282. TestHelpers.AssertDriverAttributesAre (
  283. @"
  284. 222222222222222222220
  285. 111111111111111111110",
  286. output,
  287. Application.Driver,
  288. attributes
  289. );
  290. }
  291. if (label)
  292. {
  293. root.CanFocus = true;
  294. v.CanFocus = true;
  295. Assert.True (v.HasFocus);
  296. v.SetFocus ();
  297. Assert.True (v.HasFocus);
  298. Application.LayoutAndDraw ();
  299. TestHelpers.AssertDriverAttributesAre (
  300. @"
  301. 222222222222222222220
  302. 111111111111111111110",
  303. output,
  304. Application.Driver,
  305. attributes
  306. );
  307. }
  308. Application.End (runState);
  309. top.Dispose ();
  310. }
  311. [Fact]
  312. [AutoInitShutdown]
  313. public void Correct_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Down_Right_Using_Frame ()
  314. {
  315. var label = new Label { Text = "At 0,0" };
  316. var view = new DerivedView
  317. {
  318. X = 2,
  319. Y = 2,
  320. Width = 30,
  321. Height = 2,
  322. Text = "A text with some long width\n and also with two lines."
  323. };
  324. Toplevel top = new ();
  325. top.Add (label, view);
  326. RunState runState = Application.Begin (top);
  327. Application.RunIteration (ref runState);
  328. TestHelpers.AssertDriverContentsWithFrameAre (
  329. @"
  330. At 0,0
  331. A text with some long width
  332. and also with two lines. ",
  333. output
  334. );
  335. view.Frame = new (3, 3, 10, 1);
  336. Assert.Equal (new (3, 3, 10, 1), view.Frame);
  337. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  338. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  339. //Application.Refresh();
  340. top.Draw ();
  341. TestHelpers.AssertDriverContentsWithFrameAre (
  342. @"
  343. At 0,0
  344. A text wit",
  345. output
  346. );
  347. Application.End (runState);
  348. top.Dispose ();
  349. }
  350. [Fact]
  351. [AutoInitShutdown]
  352. public void Correct_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Down_Right_Using_Pos_Dim ()
  353. {
  354. var label = new Label { Text = "At 0,0" };
  355. var view = new DerivedView
  356. {
  357. X = 2,
  358. Y = 2,
  359. Width = 30,
  360. Height = 2,
  361. Text = "A text with some long width\n and also with two lines."
  362. };
  363. Toplevel top = new ();
  364. top.Add (label, view);
  365. RunState runState = Application.Begin (top);
  366. top.Draw ();
  367. TestHelpers.AssertDriverContentsWithFrameAre (
  368. @"
  369. At 0,0
  370. A text with some long width
  371. and also with two lines. ",
  372. output
  373. );
  374. view.X = 3;
  375. view.Y = 3;
  376. view.Width = 10;
  377. view.Height = 1;
  378. Assert.Equal (new (3, 3, 10, 1), view.Frame);
  379. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  380. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  381. View.SetClipToScreen ();
  382. top.Draw ();
  383. TestHelpers.AssertDriverContentsWithFrameAre (
  384. @"
  385. At 0,0
  386. A text wit",
  387. output
  388. );
  389. Application.End (runState);
  390. top.Dispose ();
  391. }
  392. [Fact]
  393. [AutoInitShutdown]
  394. public void Correct_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Up_Left_Using_Frame ()
  395. {
  396. var label = new Label { Text = "At 0,0" };
  397. var view = new DerivedView
  398. {
  399. X = 2,
  400. Y = 2,
  401. Width = 30,
  402. Height = 2,
  403. Text = "A text with some long width\n and also with two lines."
  404. };
  405. Toplevel top = new ();
  406. top.Add (label, view);
  407. RunState runState = Application.Begin (top);
  408. Application.RunIteration (ref runState);
  409. TestHelpers.AssertDriverContentsWithFrameAre (
  410. @"
  411. At 0,0
  412. A text with some long width
  413. and also with two lines. ",
  414. output
  415. );
  416. view.Frame = new (1, 1, 10, 1);
  417. Assert.Equal (new (1, 1, 10, 1), view.Frame);
  418. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  419. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  420. top.Draw ();
  421. TestHelpers.AssertDriverContentsWithFrameAre (
  422. @"
  423. At 0,0
  424. A text wit",
  425. output
  426. );
  427. Application.End (runState);
  428. top.Dispose ();
  429. }
  430. [Fact]
  431. [AutoInitShutdown]
  432. public void Correct_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Up_Left_Using_Pos_Dim ()
  433. {
  434. var label = new Label { Text = "At 0,0" };
  435. var view = new DerivedView
  436. {
  437. X = 2,
  438. Y = 2,
  439. Width = 30,
  440. Height = 2,
  441. Text = "A text with some long width\n and also with two lines."
  442. };
  443. Toplevel top = new ();
  444. top.Add (label, view);
  445. RunState runState = Application.Begin (top);
  446. top.Draw ();
  447. TestHelpers.AssertDriverContentsWithFrameAre (
  448. @"
  449. At 0,0
  450. A text with some long width
  451. and also with two lines. ",
  452. output
  453. );
  454. view.X = 1;
  455. view.Y = 1;
  456. view.Width = 10;
  457. view.Height = 1;
  458. Assert.Equal (new (1, 1, 10, 1), view.Frame);
  459. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  460. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  461. View.SetClipToScreen ();
  462. top.Draw ();
  463. TestHelpers.AssertDriverContentsWithFrameAre (
  464. @"
  465. At 0,0
  466. A text wit",
  467. output
  468. );
  469. Application.End (runState);
  470. top.Dispose ();
  471. }
  472. [Fact]
  473. [TestRespondersDisposed]
  474. public void Dispose_View ()
  475. {
  476. var view = new View ();
  477. Assert.NotNull (view.Margin);
  478. Assert.NotNull (view.Border);
  479. Assert.NotNull (view.Padding);
  480. #if DEBUG_IDISPOSABLE
  481. Assert.Equal (4, View.Instances.Count);
  482. #endif
  483. view.Dispose ();
  484. Assert.Null (view.Margin);
  485. Assert.Null (view.Border);
  486. Assert.Null (view.Padding);
  487. }
  488. [Fact]
  489. [AutoInitShutdown]
  490. public void DrawContentComplete_Event_Is_Always_Called ()
  491. {
  492. var viewCalled = false;
  493. var tvCalled = false;
  494. var view = new View { Width = 10, Height = 10, Text = "View" };
  495. view.DrawComplete += (s, e) => viewCalled = true;
  496. var tv = new TextView { Y = 11, Width = 10, Height = 10 };
  497. tv.DrawComplete += (s, e) => tvCalled = true;
  498. var top = new Toplevel ();
  499. top.Add (view, tv);
  500. RunState runState = Application.Begin (top);
  501. Application.RunIteration (ref runState);
  502. Assert.True (viewCalled);
  503. Assert.True (tvCalled);
  504. top.Dispose ();
  505. }
  506. [Fact]
  507. [AutoInitShutdown]
  508. public void Frame_Set_After_Initialize_Update_NeededDisplay ()
  509. {
  510. var frame = new FrameView ();
  511. var label = new Label
  512. {
  513. ColorScheme = Colors.ColorSchemes ["Menu"], X = 0, Y = 0, Text = "This should be the first line."
  514. };
  515. var view = new View
  516. {
  517. X = 0, // don't overcomplicate unit tests
  518. Y = 1,
  519. Height = Dim.Auto (DimAutoStyle.Text),
  520. Width = Dim.Auto (DimAutoStyle.Text),
  521. Text = "Press me!"
  522. };
  523. frame.Add (label, view);
  524. frame.X = Pos.Center ();
  525. frame.Y = Pos.Center ();
  526. frame.Width = 40;
  527. frame.Height = 8;
  528. Toplevel top = new ();
  529. top.Add (frame);
  530. RunState runState = Application.Begin (top);
  531. top.SubviewsLaidOut += (s, e) => { Assert.Equal (new (0, 0, 80, 25), top._needsDrawRect); };
  532. frame.SubviewsLaidOut += (s, e) => { Assert.Equal (new (0, 0, 40, 8), frame._needsDrawRect); };
  533. label.SubviewsLaidOut += (s, e) => { Assert.Equal (new (0, 0, 38, 1), label._needsDrawRect); };
  534. view.SubviewsLaidOut += (s, e) => { Assert.Equal (new (0, 0, 13, 1), view._needsDrawRect); };
  535. Assert.Equal (new (0, 0, 80, 25), top.Frame);
  536. Assert.Equal (new (20, 8, 40, 8), frame.Frame);
  537. Assert.Equal (
  538. new (20, 8, 60, 16),
  539. new Rectangle (
  540. frame.Frame.Left,
  541. frame.Frame.Top,
  542. frame.Frame.Right,
  543. frame.Frame.Bottom
  544. )
  545. );
  546. Assert.Equal (new (0, 0, 30, 1), label.Frame);
  547. Assert.Equal (new (0, 1, 9, 1), view.Frame); // this proves frame was set
  548. Application.End (runState);
  549. top.Dispose ();
  550. }
  551. [Fact]
  552. public void GetHotNormalColor_ColorScheme ()
  553. {
  554. var view = new View { ColorScheme = Colors.ColorSchemes ["Base"] };
  555. Assert.Equal (view.ColorScheme.HotNormal, view.GetHotNormalColor ());
  556. view.Enabled = false;
  557. Assert.Equal (view.ColorScheme.Disabled, view.GetHotNormalColor ());
  558. view.Dispose ();
  559. }
  560. [Fact]
  561. public void GetNormalColor_ColorScheme ()
  562. {
  563. var view = new View { ColorScheme = Colors.ColorSchemes ["Base"] };
  564. Assert.Equal (view.ColorScheme.Normal, view.GetNormalColor ());
  565. view.Enabled = false;
  566. Assert.Equal (view.ColorScheme.Disabled, view.GetNormalColor ());
  567. view.Dispose ();
  568. }
  569. [Fact]
  570. [AutoInitShutdown]
  571. public void Incorrect_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Down_Right_Using_Frame ()
  572. {
  573. var label = new Label { Text = "At 0,0" };
  574. var view = new DerivedView
  575. {
  576. X = 2,
  577. Y = 2,
  578. Width = 30,
  579. Height = 2,
  580. Text = "A text with some long width\n and also with two lines."
  581. };
  582. Toplevel top = new ();
  583. top.Add (label, view);
  584. RunState runState = Application.Begin (top);
  585. Application.RunIteration (ref runState);
  586. TestHelpers.AssertDriverContentsWithFrameAre (
  587. @"
  588. At 0,0
  589. A text with some long width
  590. and also with two lines. ",
  591. output
  592. );
  593. view.Frame = new (3, 3, 10, 1);
  594. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  595. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  596. view.Draw ();
  597. TestHelpers.AssertDriverContentsWithFrameAre (
  598. @"
  599. At 0,0
  600. A text with some long width
  601. A text witith two lines. ",
  602. output
  603. );
  604. Application.End (runState);
  605. top.Dispose ();
  606. }
  607. [Fact]
  608. [AutoInitShutdown]
  609. public void Incorrect_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Down_Right_Using_Pos_Dim ()
  610. {
  611. var label = new Label { Text = "At 0,0" };
  612. var view = new DerivedView
  613. {
  614. X = 2,
  615. Y = 2,
  616. Width = 30,
  617. Height = 2,
  618. Text = "A text with some long width\n and also with two lines."
  619. };
  620. Toplevel top = new ();
  621. top.Add (label, view);
  622. RunState runState = Application.Begin (top);
  623. Application.RunIteration (ref runState);
  624. TestHelpers.AssertDriverContentsWithFrameAre (
  625. @"
  626. At 0,0
  627. A text with some long width
  628. and also with two lines. ",
  629. output
  630. );
  631. view.X = 3;
  632. view.Y = 3;
  633. view.Width = 10;
  634. view.Height = 1;
  635. Assert.Equal (new (3, 3, 10, 1), view.Frame);
  636. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  637. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  638. view.Draw ();
  639. TestHelpers.AssertDriverContentsWithFrameAre (
  640. @"
  641. At 0,0
  642. A text with some long width
  643. A text witith two lines. ",
  644. output
  645. );
  646. Application.End (runState);
  647. top.Dispose ();
  648. }
  649. [Fact]
  650. [AutoInitShutdown]
  651. public void Incorrect_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Up_Left_Using_Frame ()
  652. {
  653. var label = new Label { Text = "At 0,0" };
  654. var view = new DerivedView
  655. {
  656. X = 2,
  657. Y = 2,
  658. Width = 30,
  659. Height = 2,
  660. Text = "A text with some long width\n and also with two lines."
  661. };
  662. Toplevel top = new ();
  663. top.Add (label, view);
  664. RunState runState = Application.Begin (top);
  665. Application.RunIteration (ref runState);
  666. TestHelpers.AssertDriverContentsWithFrameAre (
  667. @"
  668. At 0,0
  669. A text with some long width
  670. and also with two lines. ",
  671. output
  672. );
  673. view.Frame = new (1, 1, 10, 1);
  674. Assert.Equal (new (1, 1, 10, 1), view.Frame);
  675. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  676. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  677. view.Draw ();
  678. TestHelpers.AssertDriverContentsWithFrameAre (
  679. @"
  680. At 0,0
  681. A text wit
  682. A text with some long width
  683. and also with two lines. ",
  684. output
  685. );
  686. Application.End (runState);
  687. top.Dispose ();
  688. }
  689. [Fact]
  690. [AutoInitShutdown]
  691. public void Incorrect_Redraw_Viewport_NeedDisplay_On_Shrink_And_Move_Up_Left_Using_Pos_Dim ()
  692. {
  693. var label = new Label { Text = "At 0,0" };
  694. var view = new DerivedView
  695. {
  696. X = 2,
  697. Y = 2,
  698. Width = 30,
  699. Height = 2,
  700. Text = "A text with some long width\n and also with two lines."
  701. };
  702. Toplevel top = new ();
  703. top.Add (label, view);
  704. RunState runState = Application.Begin (top);
  705. Application.RunIteration (ref runState);
  706. TestHelpers.AssertDriverContentsWithFrameAre (
  707. @"
  708. At 0,0
  709. A text with some long width
  710. and also with two lines. ",
  711. output
  712. );
  713. view.X = 1;
  714. view.Y = 1;
  715. view.Width = 10;
  716. view.Height = 1;
  717. Assert.Equal (new (1, 1, 10, 1), view.Frame);
  718. Assert.Equal (new (0, 0, 10, 1), view.Viewport);
  719. Assert.Equal (new (0, 0, 10, 1), view._needsDrawRect);
  720. view.Draw ();
  721. TestHelpers.AssertDriverContentsWithFrameAre (
  722. @"
  723. At 0,0
  724. A text wit
  725. A text with some long width
  726. and also with two lines. ",
  727. output
  728. );
  729. Application.End (runState);
  730. top.Dispose ();
  731. }
  732. [Fact]
  733. public void Internal_Tests ()
  734. {
  735. var rect = new Rectangle (1, 1, 10, 1);
  736. var view = new View { Frame = rect };
  737. }
  738. [Fact]
  739. [SetupFakeDriver]
  740. public void SetText_RendersCorrectly ()
  741. {
  742. View view;
  743. var text = "test";
  744. view = new Label { Text = text };
  745. view.BeginInit ();
  746. view.EndInit ();
  747. view.Draw ();
  748. TestHelpers.AssertDriverContentsWithFrameAre (text, output);
  749. }
  750. [Fact]
  751. [TestRespondersDisposed]
  752. public void New_Initializes ()
  753. {
  754. // Parameterless
  755. var r = new View ();
  756. Assert.NotNull (r);
  757. Assert.True (r.Enabled);
  758. Assert.True (r.Visible);
  759. Assert.Equal ($"View(){r.Viewport}", r.ToString ());
  760. Assert.False (r.CanFocus);
  761. Assert.False (r.HasFocus);
  762. Assert.Equal (new (0, 0, 0, 0), r.Viewport);
  763. Assert.Equal (new (0, 0, 0, 0), r.Frame);
  764. Assert.Null (r.Focused);
  765. Assert.Null (r.ColorScheme);
  766. Assert.Equal (0, r.Width);
  767. Assert.Equal (0, r.Height);
  768. Assert.Equal (0, r.X);
  769. Assert.Equal (0, r.Y);
  770. Assert.False (r.IsCurrentTop);
  771. Assert.Empty (r.Id);
  772. Assert.Empty (r.Subviews);
  773. Assert.False (r.WantContinuousButtonPressed);
  774. Assert.False (r.WantMousePositionReports);
  775. Assert.Null (r.SuperView);
  776. Assert.Null (r.MostFocused);
  777. Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
  778. r.Dispose ();
  779. // Empty Rect
  780. r = new () { Frame = Rectangle.Empty };
  781. Assert.NotNull (r);
  782. Assert.Equal ($"View(){r.Viewport}", r.ToString ());
  783. Assert.False (r.CanFocus);
  784. Assert.False (r.HasFocus);
  785. Assert.Equal (new (0, 0, 0, 0), r.Viewport);
  786. Assert.Equal (new (0, 0, 0, 0), r.Frame);
  787. Assert.Null (r.Focused);
  788. Assert.Null (r.ColorScheme);
  789. Assert.Equal (0, r.Width);
  790. Assert.Equal (0, r.Height);
  791. Assert.Equal (0, r.X);
  792. Assert.Equal (0, r.Y);
  793. Assert.False (r.IsCurrentTop);
  794. Assert.Empty (r.Id);
  795. Assert.Empty (r.Subviews);
  796. Assert.False (r.WantContinuousButtonPressed);
  797. Assert.False (r.WantMousePositionReports);
  798. Assert.Null (r.SuperView);
  799. Assert.Null (r.MostFocused);
  800. Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
  801. r.Dispose ();
  802. // Rect with values
  803. r = new () { Frame = new (1, 2, 3, 4) };
  804. Assert.NotNull (r);
  805. Assert.Equal ($"View(){r.Frame}", r.ToString ());
  806. Assert.False (r.CanFocus);
  807. Assert.False (r.HasFocus);
  808. Assert.Equal (new (0, 0, 3, 4), r.Viewport);
  809. Assert.Equal (new (1, 2, 3, 4), r.Frame);
  810. Assert.Null (r.Focused);
  811. Assert.Null (r.ColorScheme);
  812. Assert.Equal (3, r.Width);
  813. Assert.Equal (4, r.Height);
  814. Assert.Equal (1, r.X);
  815. Assert.Equal (2, r.Y);
  816. Assert.False (r.IsCurrentTop);
  817. Assert.Empty (r.Id);
  818. Assert.Empty (r.Subviews);
  819. Assert.False (r.WantContinuousButtonPressed);
  820. Assert.False (r.WantMousePositionReports);
  821. Assert.Null (r.SuperView);
  822. Assert.Null (r.MostFocused);
  823. Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
  824. r.Dispose ();
  825. // Initializes a view with a vertical direction
  826. r = new ()
  827. {
  828. Text = "Vertical View",
  829. TextDirection = TextDirection.TopBottom_LeftRight,
  830. Width = Dim.Auto (),
  831. Height = Dim.Auto ()
  832. };
  833. r.TextFormatter.WordWrap = false;
  834. Assert.NotNull (r);
  835. r.BeginInit ();
  836. r.EndInit ();
  837. Assert.False (r.CanFocus);
  838. Assert.False (r.HasFocus);
  839. Assert.Equal (new (0, 0, 1, 13), r.Viewport);
  840. Assert.Equal (new (0, 0, 1, 13), r.Frame);
  841. Assert.Null (r.Focused);
  842. Assert.Null (r.ColorScheme);
  843. Assert.False (r.IsCurrentTop);
  844. #if DEBUG
  845. Assert.Equal ("Vertical View", r.Id);
  846. #else
  847. Assert.Equal (string.Empty, r.Id);
  848. #endif
  849. Assert.Empty (r.Subviews);
  850. Assert.False (r.WantContinuousButtonPressed);
  851. Assert.False (r.WantMousePositionReports);
  852. Assert.Null (r.SuperView);
  853. Assert.Null (r.MostFocused);
  854. Assert.Equal (TextDirection.TopBottom_LeftRight, r.TextDirection);
  855. r.Dispose ();
  856. }
  857. [Fact]
  858. [TestRespondersDisposed]
  859. public void New_Methods_Return_False ()
  860. {
  861. var r = new View ();
  862. Assert.False (r.NewKeyDownEvent (Key.Empty));
  863. //Assert.False (r.OnKeyDown (new KeyEventArgs () { Key = Key.Unknown }));
  864. Assert.False (r.NewKeyUpEvent (Key.Empty));
  865. Assert.False (r.NewMouseEvent (new () { Flags = MouseFlags.AllEvents }));
  866. r.Dispose ();
  867. // TODO: Add more
  868. }
  869. [Fact]
  870. [AutoInitShutdown]
  871. public void Test_Nested_Views_With_Height_Equal_To_One ()
  872. {
  873. var v = new View { Width = 11, Height = 3, ColorScheme = new () };
  874. var top = new View { Width = Dim.Fill (), Height = 1 };
  875. var bottom = new View { Width = Dim.Fill (), Height = 1, Y = 2 };
  876. top.Add (new Label { Text = "111" });
  877. v.Add (top);
  878. v.Add (new LineView (Orientation.Horizontal) { Y = 1 });
  879. bottom.Add (new Label { Text = "222" });
  880. v.Add (bottom);
  881. v.BeginInit ();
  882. v.EndInit ();
  883. v.LayoutSubviews ();
  884. v.Draw ();
  885. var looksLike =
  886. @"
  887. 111
  888. ───────────
  889. 222";
  890. TestHelpers.AssertDriverContentsAre (looksLike, output);
  891. v.Dispose ();
  892. top.Dispose ();
  893. bottom.Dispose ();
  894. }
  895. [Fact]
  896. [TestRespondersDisposed]
  897. public void View_With_No_Difference_Between_An_Object_Initializer_Compute_And_A_Absolute ()
  898. {
  899. // Object Initializer Computed
  900. var view = new View { X = 1, Y = 2, Width = 3, Height = 4 };
  901. // Object Initializer Absolute
  902. var super = new View { Frame = new (0, 0, 10, 10) };
  903. super.Add (view);
  904. super.BeginInit ();
  905. super.EndInit ();
  906. super.LayoutSubviews ();
  907. Assert.Equal (1, view.X);
  908. Assert.Equal (2, view.Y);
  909. Assert.Equal (3, view.Width);
  910. Assert.Equal (4, view.Height);
  911. Assert.False (view.Frame.IsEmpty);
  912. Assert.Equal (new (1, 2, 3, 4), view.Frame);
  913. Assert.False (view.Viewport.IsEmpty);
  914. Assert.Equal (new (0, 0, 3, 4), view.Viewport);
  915. view.LayoutSubviews ();
  916. Assert.Equal (1, view.X);
  917. Assert.Equal (2, view.Y);
  918. Assert.Equal (3, view.Width);
  919. Assert.Equal (4, view.Height);
  920. Assert.False (view.Frame.IsEmpty);
  921. Assert.False (view.Viewport.IsEmpty);
  922. super.Dispose ();
  923. #if DEBUG_IDISPOSABLE
  924. Assert.Empty (View.Instances);
  925. #endif
  926. // Default Constructor
  927. view = new ();
  928. Assert.Equal (0, view.X);
  929. Assert.Equal (0, view.Y);
  930. Assert.Equal (0, view.Width);
  931. Assert.Equal (0, view.Height);
  932. Assert.True (view.Frame.IsEmpty);
  933. Assert.True (view.Viewport.IsEmpty);
  934. view.Dispose ();
  935. // Object Initializer
  936. view = new () { X = 1, Y = 2, Text = "" };
  937. Assert.Equal (1, view.X);
  938. Assert.Equal (2, view.Y);
  939. Assert.Equal (0, view.Width);
  940. Assert.Equal (0, view.Height);
  941. Assert.False (view.Frame.IsEmpty);
  942. Assert.True (view.Viewport.IsEmpty);
  943. view.Dispose ();
  944. // Default Constructor and post assignment equivalent to Object Initializer
  945. view = new ();
  946. view.X = 1;
  947. view.Y = 2;
  948. view.Width = 3;
  949. view.Height = 4;
  950. super = new () { Frame = new (0, 0, 10, 10) };
  951. super.Add (view);
  952. super.BeginInit ();
  953. super.EndInit ();
  954. super.LayoutSubviews ();
  955. Assert.Equal (1, view.X);
  956. Assert.Equal (2, view.Y);
  957. Assert.Equal (3, view.Width);
  958. Assert.Equal (4, view.Height);
  959. Assert.False (view.Frame.IsEmpty);
  960. Assert.Equal (new (1, 2, 3, 4), view.Frame);
  961. Assert.False (view.Viewport.IsEmpty);
  962. Assert.Equal (new (0, 0, 3, 4), view.Viewport);
  963. super.Dispose ();
  964. }
  965. [Fact]
  966. [AutoInitShutdown]
  967. public void Visible_Clear_The_View_Output ()
  968. {
  969. var view = new View { Text = "Testing visibility." }; // use View, not Label to avoid AutoSize == true
  970. Assert.Equal (0, view.Frame.Width);
  971. Assert.Equal (0, view.Height);
  972. var win = new Window ();
  973. win.Add (view);
  974. Toplevel top = new ();
  975. top.Add (win);
  976. RunState rs = Application.Begin (top);
  977. view.Width = Dim.Auto ();
  978. view.Height = Dim.Auto ();
  979. Application.RunIteration (ref rs);
  980. Assert.Equal ("Testing visibility.".Length, view.Frame.Width);
  981. Assert.True (view.Visible);
  982. ((FakeDriver)Application.Driver!).SetBufferSize (30, 5);
  983. TestHelpers.AssertDriverContentsWithFrameAre (
  984. @"
  985. ┌────────────────────────────┐
  986. │Testing visibility. │
  987. │ │
  988. │ │
  989. └────────────────────────────┘
  990. ",
  991. output
  992. );
  993. view.Visible = false;
  994. var firstIteration = false;
  995. Application.RunIteration (ref rs, firstIteration);
  996. TestHelpers.AssertDriverContentsWithFrameAre (
  997. @"
  998. ┌────────────────────────────┐
  999. │ │
  1000. │ │
  1001. │ │
  1002. └────────────────────────────┘
  1003. ",
  1004. output
  1005. );
  1006. Application.End (rs);
  1007. top.Dispose ();
  1008. }
  1009. [Fact]
  1010. [AutoInitShutdown]
  1011. public void Visible_Sets_Also_Sets_Subviews ()
  1012. {
  1013. var button = new Button { Text = "Click Me" };
  1014. var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
  1015. win.Add (button);
  1016. Toplevel top = new ();
  1017. top.Add (win);
  1018. var iterations = 0;
  1019. Application.Iteration += (s, a) =>
  1020. {
  1021. iterations++;
  1022. Assert.True (button.Visible);
  1023. Assert.True (button.CanFocus);
  1024. Assert.True (button.HasFocus);
  1025. Assert.True (win.Visible);
  1026. Assert.True (win.CanFocus);
  1027. Assert.True (win.HasFocus);
  1028. win.Visible = false;
  1029. Assert.True (button.Visible);
  1030. Assert.True (button.CanFocus);
  1031. Assert.False (button.HasFocus);
  1032. Assert.False (win.Visible);
  1033. Assert.True (win.CanFocus);
  1034. Assert.False (win.HasFocus);
  1035. button.SetFocus ();
  1036. Assert.False (button.HasFocus);
  1037. Assert.False (win.HasFocus);
  1038. win.SetFocus ();
  1039. Assert.False (button.HasFocus);
  1040. Assert.False (win.HasFocus);
  1041. win.Visible = true;
  1042. Assert.True (button.HasFocus);
  1043. Assert.True (win.HasFocus);
  1044. Application.RequestStop ();
  1045. };
  1046. Application.Run (top);
  1047. top.Dispose ();
  1048. Assert.Equal (1, iterations);
  1049. }
  1050. public class DerivedView : View
  1051. {
  1052. public DerivedView () { CanFocus = true; }
  1053. public bool IsKeyDown { get; set; }
  1054. public bool IsKeyPress { get; set; }
  1055. public bool IsKeyUp { get; set; }
  1056. public override string Text { get; set; }
  1057. protected override bool OnDrawingContent ()
  1058. {
  1059. var idx = 0;
  1060. // BUGBUG: v2 - this should use Viewport, not Frame
  1061. for (var r = 0; r < Frame.Height; r++)
  1062. {
  1063. for (var c = 0; c < Frame.Width; c++)
  1064. {
  1065. if (idx < Text.Length)
  1066. {
  1067. char rune = Text [idx];
  1068. if (rune != '\n')
  1069. {
  1070. AddRune (c, r, (Rune)Text [idx]);
  1071. }
  1072. idx++;
  1073. if (rune == '\n')
  1074. {
  1075. break;
  1076. }
  1077. }
  1078. }
  1079. }
  1080. ClearNeedsDraw ();
  1081. return true;
  1082. }
  1083. protected override bool OnKeyDown (Key keyEvent)
  1084. {
  1085. IsKeyDown = true;
  1086. return true;
  1087. }
  1088. public override bool OnKeyUp (Key keyEvent)
  1089. {
  1090. IsKeyUp = true;
  1091. return true;
  1092. }
  1093. protected override bool OnKeyDownNotHandled (Key keyEvent)
  1094. {
  1095. IsKeyPress = true;
  1096. return true;
  1097. }
  1098. }
  1099. }