DrawTests.cs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. #nullable enable
  2. using System.Text;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewTests;
  5. [Trait ("Category", "Output")]
  6. public class DrawTests (ITestOutputHelper _output)
  7. {
  8. [Fact]
  9. [SetupFakeDriver]
  10. public void Move_Is_Constrained_To_Viewport ()
  11. {
  12. var view = new View
  13. {
  14. X = 1,
  15. Y = 1,
  16. Width = 3, Height = 3
  17. };
  18. view.Margin.Thickness = new (1);
  19. // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen)
  20. view.Move (0, 0);
  21. Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
  22. view.Move (-1, -1);
  23. Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
  24. view.Move (1, 1);
  25. Assert.Equal (new (2, 2), new Point (Application.Driver!.Col, Application.Driver!.Row));
  26. }
  27. [Fact]
  28. [SetupFakeDriver]
  29. public void AddRune_Is_Constrained_To_Viewport ()
  30. {
  31. var view = new View
  32. {
  33. X = 1,
  34. Y = 1,
  35. Width = 3, Height = 3
  36. };
  37. view.Margin.Thickness = new (1);
  38. view.Margin.Diagnostics = ViewDiagnosticFlags.Thickness;
  39. view.BeginInit ();
  40. view.EndInit ();
  41. view.Draw ();
  42. // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen)
  43. Assert.Equal ((Rune)' ', Application.Driver?.Contents! [2, 2].Rune);
  44. view.AddRune (0, 0, Rune.ReplacementChar);
  45. Assert.Equal (Rune.ReplacementChar, Application.Driver?.Contents! [2, 2].Rune);
  46. view.AddRune (-1, -1, Rune.ReplacementChar);
  47. Assert.Equal ((Rune)'M', Application.Driver?.Contents! [1, 1].Rune);
  48. view.AddRune (1, 1, Rune.ReplacementChar);
  49. Assert.Equal ((Rune)'M', Application.Driver?.Contents! [3, 3].Rune);
  50. }
  51. [Theory]
  52. [InlineData (0, 0, 1, 1)]
  53. [InlineData (0, 0, 2, 2)]
  54. [InlineData (-1, -1, 2, 2)]
  55. [SetupFakeDriver]
  56. public void FillRect_Fills_HonorsClip (int x, int y, int width, int height)
  57. {
  58. var superView = new View { Width = Dim.Fill (), Height = Dim.Fill () };
  59. var view = new View
  60. {
  61. Text = "X",
  62. X = 1, Y = 1,
  63. Width = 3, Height = 3,
  64. BorderStyle = LineStyle.Single
  65. };
  66. superView.Add (view);
  67. superView.BeginInit ();
  68. superView.EndInit ();
  69. superView.LayoutSubviews ();
  70. superView.Draw ();
  71. TestHelpers.AssertDriverContentsWithFrameAre (
  72. @"
  73. ┌─┐
  74. │X│
  75. └─┘",
  76. _output);
  77. Rectangle toFill = new (x, y, width, height);
  78. view.FillRect (toFill);
  79. TestHelpers.AssertDriverContentsWithFrameAre (
  80. @"
  81. ┌─┐
  82. │ │
  83. └─┘",
  84. _output);
  85. // Now try to clear beyond Viewport (invalid; clipping should prevent)
  86. superView.SetNeedsDraw ();
  87. superView.Draw ();
  88. TestHelpers.AssertDriverContentsWithFrameAre (
  89. @"
  90. ┌─┐
  91. │X│
  92. └─┘",
  93. _output);
  94. toFill = new (-width, -height, width, height);
  95. view.FillRect (toFill);
  96. TestHelpers.AssertDriverContentsWithFrameAre (
  97. @"
  98. ┌─┐
  99. │X│
  100. └─┘",
  101. _output);
  102. // Now try to clear beyond Viewport (valid)
  103. superView.SetNeedsDraw ();
  104. superView.Draw ();
  105. TestHelpers.AssertDriverContentsWithFrameAre (
  106. @"
  107. ┌─┐
  108. │X│
  109. └─┘",
  110. _output);
  111. toFill = new (-1, -1, width + 1, height + 1);
  112. view.FillRect (toFill);
  113. TestHelpers.AssertDriverContentsWithFrameAre (
  114. @"
  115. ┌─┐
  116. │ │
  117. └─┘",
  118. _output);
  119. // Now clear too much size
  120. superView.SetNeedsDraw ();
  121. superView.Draw ();
  122. TestHelpers.AssertDriverContentsWithFrameAre (
  123. @"
  124. ┌─┐
  125. │X│
  126. └─┘",
  127. _output);
  128. toFill = new (0, 0, width * 2, height * 2);
  129. view.FillRect (toFill);
  130. TestHelpers.AssertDriverContentsWithFrameAre (
  131. @"
  132. ┌─┐
  133. │ │
  134. └─┘",
  135. _output);
  136. }
  137. [Fact]
  138. [SetupFakeDriver]
  139. public void Clear_ClearsEntireViewport ()
  140. {
  141. var superView = new View { Width = Dim.Fill (), Height = Dim.Fill () };
  142. var view = new View
  143. {
  144. Text = "X",
  145. X = 1, Y = 1,
  146. Width = 3, Height = 3,
  147. BorderStyle = LineStyle.Single
  148. };
  149. superView.Add (view);
  150. superView.BeginInit ();
  151. superView.EndInit ();
  152. superView.LayoutSubviews ();
  153. superView.Draw ();
  154. TestHelpers.AssertDriverContentsWithFrameAre (
  155. @"
  156. ┌─┐
  157. │X│
  158. └─┘",
  159. _output);
  160. view.ClearViewport ();
  161. TestHelpers.AssertDriverContentsWithFrameAre (
  162. @"
  163. ┌─┐
  164. │ │
  165. └─┘",
  166. _output);
  167. }
  168. [Fact]
  169. [SetupFakeDriver]
  170. public void Clear_WithClearVisibleContentOnly_ClearsVisibleContentOnly ()
  171. {
  172. var superView = new View { Width = Dim.Fill (), Height = Dim.Fill () };
  173. var view = new View
  174. {
  175. Text = "X",
  176. X = 1, Y = 1,
  177. Width = 3, Height = 3,
  178. BorderStyle = LineStyle.Single,
  179. ViewportSettings = ViewportSettings.ClearContentOnly
  180. };
  181. superView.Add (view);
  182. superView.BeginInit ();
  183. superView.EndInit ();
  184. superView.LayoutSubviews ();
  185. superView.Draw ();
  186. TestHelpers.AssertDriverContentsWithFrameAre (
  187. @"
  188. ┌─┐
  189. │X│
  190. └─┘",
  191. _output);
  192. view.ClearViewport ();
  193. TestHelpers.AssertDriverContentsWithFrameAre (
  194. @"
  195. ┌─┐
  196. │ │
  197. └─┘",
  198. _output);
  199. }
  200. [Fact]
  201. [AutoInitShutdown]
  202. [Trait ("Category", "Unicode")]
  203. public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two ()
  204. {
  205. const string us = "\U0000f900";
  206. var r = (Rune)0xf900;
  207. Assert.Equal ("豈", us);
  208. Assert.Equal ("豈", r.ToString ());
  209. Assert.Equal (us, r.ToString ());
  210. Assert.Equal (2, us.GetColumns ());
  211. Assert.Equal (2, r.GetColumns ());
  212. var win = new Window { Title = us };
  213. var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill () };
  214. var tf = new TextField { Text = us, Y = 1, Width = 3 };
  215. win.Add (view, tf);
  216. Toplevel top = new ();
  217. top.Add (win);
  218. Application.Begin (top);
  219. ((FakeDriver)Application.Driver!).SetBufferSize (10, 4);
  220. const string expectedOutput = """
  221. ┌┤豈├────┐
  222. │豈 │
  223. │豈 │
  224. └────────┘
  225. """;
  226. TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  227. TestHelpers.AssertDriverContentsAre (expectedOutput, _output);
  228. // This test has nothing to do with color - removing as it is not relevant and fragile
  229. top.Dispose ();
  230. }
  231. // TODO: Refactor this test to not depend on TextView etc... Make it as primitive as possible
  232. [Fact]
  233. [AutoInitShutdown]
  234. [Trait ("Category", "Unicode")]
  235. public void Clipping_AddRune_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
  236. {
  237. var tv = new TextView
  238. {
  239. Width = Dim.Fill (),
  240. Height = Dim.Fill (),
  241. Text = """
  242. これは広いルーンラインです。
  243. これは広いルーンラインです。
  244. これは広いルーンラインです。
  245. これは広いルーンラインです。
  246. これは広いルーンラインです。
  247. これは広いルーンラインです。
  248. これは広いルーンラインです。
  249. これは広いルーンラインです。
  250. """
  251. };
  252. var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
  253. win.Add (tv);
  254. var top = new Toplevel ();
  255. top.Add (win);
  256. var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
  257. // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
  258. var dg = new Window { X = 2, Y = 2, Width = 14, Height = 3 };
  259. dg.Add (view);
  260. RunState rsTop = Application.Begin (top);
  261. RunState rsDiag = Application.Begin (dg);
  262. ((FakeDriver)Application.Driver!).SetBufferSize (30, 10);
  263. const string expectedOutput = """
  264. ┌────────────────────────────┐
  265. │これは広いルーンラインです。│
  266. │�┌────────────┐�ラインです。│
  267. │�│ワイドルーン│�ラインです。│
  268. │�└────────────┘�ラインです。│
  269. │これは広いルーンラインです。│
  270. │これは広いルーンラインです。│
  271. │これは広いルーンラインです。│
  272. │これは広いルーンラインです。│
  273. └────────────────────────────┘
  274. """;
  275. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  276. Assert.Equal (new (0, 0, 30, 10), pos);
  277. Application.End (rsDiag);
  278. dg.Dispose ();
  279. Application.End (rsTop);
  280. top.Dispose ();
  281. }
  282. [Fact]
  283. [AutoInitShutdown]
  284. [Trait ("Category", "Output")]
  285. public void Colors_On_TextAlignment_Right_And_Bottom ()
  286. {
  287. var viewRight = new View
  288. {
  289. Text = "Test",
  290. Width = 6,
  291. Height = 1,
  292. TextAlignment = Alignment.End,
  293. ColorScheme = Colors.ColorSchemes ["Base"]
  294. };
  295. var viewBottom = new View
  296. {
  297. Text = "Test",
  298. TextDirection = TextDirection.TopBottom_LeftRight,
  299. Y = 1,
  300. Width = 1,
  301. Height = 6,
  302. VerticalTextAlignment = Alignment.End,
  303. ColorScheme = Colors.ColorSchemes ["Base"]
  304. };
  305. Toplevel top = new ();
  306. top.Add (viewRight, viewBottom);
  307. var rs = Application.Begin (top);
  308. ((FakeDriver)Application.Driver!).SetBufferSize (7, 7);
  309. Application.RunIteration (ref rs);
  310. TestHelpers.AssertDriverContentsWithFrameAre (
  311. """
  312. Test
  313. T
  314. e
  315. s
  316. t
  317. """,
  318. _output
  319. );
  320. TestHelpers.AssertDriverAttributesAre (
  321. """
  322. 000000
  323. 0
  324. 0
  325. 0
  326. 0
  327. 0
  328. 0
  329. """,
  330. _output,
  331. Application.Driver,
  332. Colors.ColorSchemes ["Base"]!.Normal
  333. );
  334. top.Dispose ();
  335. }
  336. [Fact]
  337. [SetupFakeDriver]
  338. public void Draw_Minimum_Full_Border_With_Empty_Viewport ()
  339. {
  340. var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
  341. Assert.True (view.NeedsLayout);
  342. Assert.True (view.NeedsDraw);
  343. view.Layout ();
  344. Assert.Equal (new (0, 0, 2, 2), view.Frame);
  345. Assert.Equal (Rectangle.Empty, view.Viewport);
  346. Assert.True (view.NeedsDraw);
  347. view.Draw ();
  348. TestHelpers.AssertDriverContentsWithFrameAre (
  349. """
  350. ┌┐
  351. └┘
  352. """,
  353. _output
  354. );
  355. }
  356. [Fact]
  357. [SetupFakeDriver]
  358. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Bottom ()
  359. {
  360. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  361. view.Border.Thickness = new (1, 1, 1, 0);
  362. view.BeginInit ();
  363. view.EndInit ();
  364. view.SetRelativeLayout (Application.Screen.Size);
  365. Assert.Equal (new (0, 0, 2, 1), view.Frame);
  366. Assert.Equal (Rectangle.Empty, view.Viewport);
  367. view.Draw ();
  368. TestHelpers.AssertDriverContentsWithFrameAre ("──", _output);
  369. }
  370. [Fact]
  371. [SetupFakeDriver]
  372. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Left ()
  373. {
  374. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  375. view.Border.Thickness = new (0, 1, 1, 1);
  376. view.BeginInit ();
  377. view.EndInit ();
  378. view.SetRelativeLayout (Application.Screen.Size);
  379. Assert.Equal (new (0, 0, 1, 2), view.Frame);
  380. Assert.Equal (Rectangle.Empty, view.Viewport);
  381. view.Draw ();
  382. TestHelpers.AssertDriverContentsWithFrameAre (
  383. """
  384. """,
  385. _output
  386. );
  387. }
  388. [Fact]
  389. [SetupFakeDriver]
  390. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Right ()
  391. {
  392. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  393. view.Border.Thickness = new (1, 1, 0, 1);
  394. view.BeginInit ();
  395. view.EndInit ();
  396. view.SetRelativeLayout (Application.Screen.Size);
  397. Assert.Equal (new (0, 0, 1, 2), view.Frame);
  398. Assert.Equal (Rectangle.Empty, view.Viewport);
  399. view.Draw ();
  400. TestHelpers.AssertDriverContentsWithFrameAre (
  401. """
  402. """,
  403. _output
  404. );
  405. }
  406. [Fact]
  407. [SetupFakeDriver]
  408. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Top ()
  409. {
  410. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  411. view.Border.Thickness = new (1, 0, 1, 1);
  412. view.BeginInit ();
  413. view.EndInit ();
  414. view.SetRelativeLayout (Application.Screen.Size);
  415. Assert.Equal (new (0, 0, 2, 1), view.Frame);
  416. Assert.Equal (Rectangle.Empty, view.Viewport);
  417. view.Draw ();
  418. TestHelpers.AssertDriverContentsWithFrameAre (
  419. "││",
  420. _output
  421. );
  422. }
  423. [Fact]
  424. [AutoInitShutdown]
  425. public void Draw_Negative_Viewport_Horizontal_With_New_Lines ()
  426. {
  427. var subView = new View
  428. {
  429. Id = "subView",
  430. X = 1,
  431. Width = 1,
  432. Height = 7,
  433. Text = """
  434. s
  435. u
  436. b
  437. V
  438. i
  439. e
  440. w
  441. """
  442. };
  443. var view = new View
  444. {
  445. Id = "view", Width = 2, Height = 20, Text = """
  446. 0
  447. 1
  448. 2
  449. 3
  450. 4
  451. 5
  452. 6
  453. 7
  454. 8
  455. 9
  456. 0
  457. 1
  458. 2
  459. 3
  460. 4
  461. 5
  462. 6
  463. 7
  464. 8
  465. 9
  466. """
  467. };
  468. view.Add (subView);
  469. var content = new View { Id = "content", Width = 20, Height = 20 };
  470. content.Add (view);
  471. var container = new View
  472. {
  473. Id = "container",
  474. X = 1,
  475. Y = 1,
  476. Width = 5,
  477. Height = 5
  478. };
  479. container.Add (content);
  480. Toplevel top = new ();
  481. top.Add (container);
  482. var rs = Application.Begin (top);
  483. top.Draw ();
  484. TestHelpers.AssertDriverContentsWithFrameAre (
  485. """
  486. 0s
  487. 1u
  488. 2b
  489. 3V
  490. 4i
  491. """,
  492. _output
  493. );
  494. content.X = -1;
  495. Application.LayoutAndDrawToplevels ();
  496. TestHelpers.AssertDriverContentsWithFrameAre (
  497. """
  498. s
  499. u
  500. b
  501. V
  502. i
  503. """,
  504. _output
  505. );
  506. content.X = -2;
  507. Application.LayoutAndDrawToplevels ();
  508. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  509. content.X = 0;
  510. content.Y = -1;
  511. Application.LayoutAndDrawToplevels ();
  512. TestHelpers.AssertDriverContentsWithFrameAre (
  513. """
  514. 1u
  515. 2b
  516. 3V
  517. 4i
  518. 5e
  519. """,
  520. _output
  521. );
  522. content.Y = -6;
  523. Application.LayoutAndDrawToplevels ();
  524. TestHelpers.AssertDriverContentsWithFrameAre (
  525. """
  526. 6w
  527. 7
  528. 8
  529. 9
  530. 0
  531. """,
  532. _output
  533. );
  534. content.Y = -19;
  535. Application.LayoutAndDrawToplevels ();
  536. TestHelpers.AssertDriverContentsWithFrameAre (
  537. """
  538. 9
  539. """,
  540. _output
  541. );
  542. content.Y = -20;
  543. Application.LayoutAndDrawToplevels ();
  544. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  545. content.X = -2;
  546. content.Y = 0;
  547. Application.LayoutAndDrawToplevels ();
  548. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  549. top.Dispose ();
  550. }
  551. [Fact]
  552. [AutoInitShutdown]
  553. public void Draw_Negative_Viewport_Horizontal_Without_New_Lines ()
  554. {
  555. // BUGBUG: This previously assumed the default height of a View was 1.
  556. var subView = new View
  557. {
  558. Id = "subView",
  559. Y = 1,
  560. Width = 7,
  561. Height = 1,
  562. Text = "subView"
  563. };
  564. var view = new View { Id = "view", Width = 20, Height = 2, Text = "01234567890123456789" };
  565. view.Add (subView);
  566. var content = new View { Id = "content", Width = 20, Height = 20 };
  567. content.Add (view);
  568. var container = new View
  569. {
  570. Id = "container",
  571. X = 1,
  572. Y = 1,
  573. Width = 5,
  574. Height = 5
  575. };
  576. container.Add (content);
  577. Toplevel top = new ();
  578. top.Add (container);
  579. // BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
  580. top.SubviewsLaidOut += Top_LayoutComplete;
  581. Application.Begin (top);
  582. Application.LayoutAndDrawToplevels ();
  583. TestHelpers.AssertDriverContentsWithFrameAre (
  584. """
  585. 01234
  586. subVi
  587. """,
  588. _output
  589. );
  590. content.X = -1;
  591. Application.LayoutAndDrawToplevels ();
  592. TestHelpers.AssertDriverContentsWithFrameAre (
  593. """
  594. 12345
  595. ubVie
  596. """,
  597. _output
  598. );
  599. content.Y = -1;
  600. Application.LayoutAndDrawToplevels ();
  601. TestHelpers.AssertDriverContentsWithFrameAre (
  602. """
  603. ubVie
  604. """,
  605. _output
  606. );
  607. content.Y = -2;
  608. Application.LayoutAndDrawToplevels ();
  609. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  610. content.X = -20;
  611. content.Y = 0;
  612. Application.LayoutAndDrawToplevels ();
  613. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  614. top.Dispose ();
  615. return;
  616. void Top_LayoutComplete (object? sender, LayoutEventArgs e) { Application.Driver!.Clip = new (container.Frame); }
  617. }
  618. [Fact]
  619. [AutoInitShutdown]
  620. public void Draw_Negative_Viewport_Vertical ()
  621. {
  622. var subView = new View
  623. {
  624. Id = "subView",
  625. X = 1,
  626. Width = 1,
  627. Height = 7,
  628. Text = "subView",
  629. TextDirection = TextDirection.TopBottom_LeftRight
  630. };
  631. var view = new View
  632. {
  633. Id = "view",
  634. Width = 2,
  635. Height = 20,
  636. Text = "01234567890123456789",
  637. TextDirection = TextDirection.TopBottom_LeftRight
  638. };
  639. view.Add (subView);
  640. var content = new View { Id = "content", Width = 20, Height = 20 };
  641. content.Add (view);
  642. var container = new View
  643. {
  644. Id = "container",
  645. X = 1,
  646. Y = 1,
  647. Width = 5,
  648. Height = 5
  649. };
  650. container.Add (content);
  651. Toplevel top = new ();
  652. top.Add (container);
  653. Application.Begin (top);
  654. Application.LayoutAndDrawToplevels ();
  655. TestHelpers.AssertDriverContentsWithFrameAre (
  656. """
  657. 0s
  658. 1u
  659. 2b
  660. 3V
  661. 4i
  662. """,
  663. _output
  664. );
  665. content.X = -1;
  666. Application.LayoutAndDrawToplevels ();
  667. TestHelpers.AssertDriverContentsWithFrameAre (
  668. """
  669. s
  670. u
  671. b
  672. V
  673. i
  674. """,
  675. _output
  676. );
  677. content.X = -2;
  678. Application.LayoutAndDrawToplevels ();
  679. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  680. content.X = 0;
  681. content.Y = -1;
  682. Application.LayoutAndDrawToplevels ();
  683. TestHelpers.AssertDriverContentsWithFrameAre (
  684. """
  685. 1u
  686. 2b
  687. 3V
  688. 4i
  689. 5e
  690. """,
  691. _output
  692. );
  693. content.Y = -6;
  694. Application.LayoutAndDrawToplevels ();
  695. TestHelpers.AssertDriverContentsWithFrameAre (
  696. """
  697. 6w
  698. 7
  699. 8
  700. 9
  701. 0
  702. """,
  703. _output
  704. );
  705. content.Y = -19;
  706. Application.LayoutAndDrawToplevels ();
  707. TestHelpers.AssertDriverContentsWithFrameAre (
  708. """
  709. 9
  710. """,
  711. _output
  712. );
  713. content.Y = -20;
  714. Application.LayoutAndDrawToplevels ();
  715. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  716. content.X = -2;
  717. content.Y = 0;
  718. Application.LayoutAndDrawToplevels ();
  719. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  720. top.Dispose ();
  721. }
  722. [Theory]
  723. [SetupFakeDriver]
  724. [InlineData ("𝔽𝕆𝕆𝔹𝔸R")]
  725. [InlineData ("a𐐀b")]
  726. public void DrawHotString_NonBmp (string expected)
  727. {
  728. var view = new View { Width = 10, Height = 1 };
  729. view.DrawHotString (expected, Attribute.Default, Attribute.Default);
  730. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  731. }
  732. // TODO: The tests below that use Label should use View instead.
  733. [Fact]
  734. [AutoInitShutdown]
  735. public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
  736. {
  737. var us = "\U0001d539";
  738. var r = (Rune)0x1d539;
  739. Assert.Equal ("𝔹", us);
  740. Assert.Equal ("𝔹", r.ToString ());
  741. Assert.Equal (us, r.ToString ());
  742. Assert.Equal (1, us.GetColumns ());
  743. Assert.Equal (1, r.GetColumns ());
  744. var win = new Window { Title = us };
  745. var view = new Label { Text = r.ToString () };
  746. var tf = new TextField { Text = us, Y = 1, Width = 3 };
  747. win.Add (view, tf);
  748. Toplevel top = new ();
  749. top.Add (win);
  750. Application.Begin (top);
  751. ((FakeDriver)Application.Driver!).SetBufferSize (10, 4);
  752. var expected = """
  753. ┌┤𝔹├─────┐
  754. │𝔹 │
  755. │𝔹 │
  756. └────────┘
  757. """;
  758. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  759. TestHelpers.AssertDriverContentsAre (expected, _output);
  760. top.Dispose ();
  761. // This test has nothing to do with color - removing as it is not relevant and fragile
  762. }
  763. [Fact]
  764. [SetupFakeDriver]
  765. public void SetClip_ClipVisibleContentOnly_VisibleContentIsClipped ()
  766. {
  767. // Screen is 25x25
  768. // View is 25x25
  769. // Viewport is (0, 0, 23, 23)
  770. // ContentSize is (10, 10)
  771. // ViewportToScreen is (1, 1, 23, 23)
  772. // Visible content is (1, 1, 10, 10)
  773. // Expected clip is (1, 1, 10, 10) - same as visible content
  774. Rectangle expectedClip = new (1, 1, 10, 10);
  775. // Arrange
  776. var view = new View
  777. {
  778. Width = Dim.Fill (),
  779. Height = Dim.Fill (),
  780. ViewportSettings = ViewportSettings.ClipContentOnly
  781. };
  782. view.SetContentSize (new Size (10, 10));
  783. view.Border.Thickness = new (1);
  784. view.BeginInit ();
  785. view.EndInit ();
  786. Assert.Equal (view.Frame, Application.Driver?.Clip?.GetBounds ());
  787. // Act
  788. view.SetClipToViewport ();
  789. // Assert
  790. Assert.Equal (expectedClip, Application.Driver?.Clip?.GetBounds());
  791. view.Dispose ();
  792. }
  793. [Fact]
  794. [SetupFakeDriver]
  795. public void SetClip_Default_ClipsToViewport ()
  796. {
  797. // Screen is 25x25
  798. // View is 25x25
  799. // Viewport is (0, 0, 23, 23)
  800. // ContentSize is (10, 10)
  801. // ViewportToScreen is (1, 1, 23, 23)
  802. // Visible content is (1, 1, 10, 10)
  803. // Expected clip is (1, 1, 23, 23) - same as Viewport
  804. Rectangle expectedClip = new (1, 1, 23, 23);
  805. // Arrange
  806. var view = new View
  807. {
  808. Width = Dim.Fill (),
  809. Height = Dim.Fill ()
  810. };
  811. view.SetContentSize (new Size (10, 10));
  812. view.Border.Thickness = new (1);
  813. view.BeginInit ();
  814. view.EndInit ();
  815. Assert.Equal (view.Frame, Application.Driver?.Clip.GetBounds ());
  816. view.Viewport = view.Viewport with { X = 1, Y = 1 };
  817. // Act
  818. view.SetClipToViewport ();
  819. // Assert
  820. Assert.Equal (expectedClip, Application.Driver?.Clip.GetBounds ());
  821. view.Dispose ();
  822. }
  823. [Fact]
  824. [TestRespondersDisposed]
  825. public void Draw_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
  826. {
  827. Application.Init (new FakeDriver ());
  828. Toplevel top = new ();
  829. var view = new View { X = -2, Text = "view" };
  830. top.Add (view);
  831. Application.Iteration += (s, a) =>
  832. {
  833. Assert.Equal (-2, view.X);
  834. Application.RequestStop ();
  835. };
  836. try
  837. {
  838. Application.Run (top);
  839. }
  840. catch (IndexOutOfRangeException ex)
  841. {
  842. // After the fix this exception will not be caught.
  843. Assert.IsType<IndexOutOfRangeException> (ex);
  844. }
  845. top.Dispose ();
  846. // Shutdown must be called to safely clean up Application if Init has been called
  847. Application.Shutdown ();
  848. }
  849. }