DrawTests.cs 35 KB

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