DrawTests.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  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 Thickness (1);
  19. // Only valid location w/in Viewport is 0, 0 (view) - 2, 2 (screen)
  20. view.Move (0, 0);
  21. Assert.Equal (new Point (2, 2), new Point (Application.Driver.Col, Application.Driver.Row));
  22. view.Move (-1, -1);
  23. Assert.Equal (new Point (2, 2), new Point (Application.Driver.Col, Application.Driver.Row));
  24. view.Move (1, 1);
  25. Assert.Equal (new Point (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 Thickness (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. // Don't use Label. It sets AutoSize = true which is not what we're testing here.
  258. var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
  259. // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
  260. var dg = new Window { X = 2, Y = 2, Width = 14, Height = 3 };
  261. dg.Add (view);
  262. RunState rsTop = Application.Begin (top);
  263. RunState rsDiag = Application.Begin (dg);
  264. ((FakeDriver)Application.Driver).SetBufferSize (30, 10);
  265. const string expectedOutput = """
  266. ┌────────────────────────────┐
  267. │これは広いルーンラインです。│
  268. │�┌────────────┐�ラインです。│
  269. │�│ワイドルーン│�ラインです。│
  270. │�└────────────┘�ラインです。│
  271. │これは広いルーンラインです。│
  272. │これは広いルーンラインです。│
  273. │これは広いルーンラインです。│
  274. │これは広いルーンラインです。│
  275. └────────────────────────────┘
  276. """;
  277. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  278. Assert.Equal (new Rectangle (0, 0, 30, 10), pos);
  279. Application.End (rsDiag);
  280. dg.Dispose ();
  281. Application.End (rsTop);
  282. top.Dispose ();
  283. }
  284. [Fact]
  285. [AutoInitShutdown]
  286. [Trait ("Category", "Output")]
  287. public void Colors_On_TextAlignment_Right_And_Bottom ()
  288. {
  289. var viewRight = new View
  290. {
  291. Text = "Test",
  292. Width = 6,
  293. Height = 1,
  294. TextAlignment = Alignment.End,
  295. ColorScheme = Colors.ColorSchemes ["Base"]
  296. };
  297. var viewBottom = new View
  298. {
  299. Text = "Test",
  300. TextDirection = TextDirection.TopBottom_LeftRight,
  301. Y = 1,
  302. Width = 1,
  303. Height = 6,
  304. VerticalTextAlignment = Alignment.End,
  305. ColorScheme = Colors.ColorSchemes ["Base"]
  306. };
  307. Toplevel top = new ();
  308. top.Add (viewRight, viewBottom);
  309. Application.Begin (top);
  310. ((FakeDriver)Application.Driver).SetBufferSize (7, 7);
  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. 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. view.BeginInit ();
  342. view.EndInit ();
  343. view.SetRelativeLayout (Application.Screen.Size);
  344. Assert.Equal (new (0, 0, 2, 2), view.Frame);
  345. Assert.Equal (Rectangle.Empty, view.Viewport);
  346. view.Draw ();
  347. TestHelpers.AssertDriverContentsWithFrameAre (
  348. """
  349. ┌┐
  350. └┘
  351. """,
  352. _output
  353. );
  354. }
  355. [Fact]
  356. [SetupFakeDriver]
  357. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Bottom ()
  358. {
  359. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  360. view.Border.Thickness = new Thickness (1, 1, 1, 0);
  361. view.BeginInit ();
  362. view.EndInit ();
  363. view.SetRelativeLayout (Application.Screen.Size);
  364. Assert.Equal (new (0, 0, 2, 1), view.Frame);
  365. Assert.Equal (Rectangle.Empty, view.Viewport);
  366. view.Draw ();
  367. TestHelpers.AssertDriverContentsWithFrameAre ("──", _output);
  368. }
  369. [Fact]
  370. [SetupFakeDriver]
  371. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Left ()
  372. {
  373. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  374. view.Border.Thickness = new Thickness (0, 1, 1, 1);
  375. view.BeginInit ();
  376. view.EndInit ();
  377. view.SetRelativeLayout (Application.Screen.Size);
  378. Assert.Equal (new (0, 0, 1, 2), view.Frame);
  379. Assert.Equal (Rectangle.Empty, view.Viewport);
  380. view.Draw ();
  381. TestHelpers.AssertDriverContentsWithFrameAre (
  382. """
  383. """,
  384. _output
  385. );
  386. }
  387. [Fact]
  388. [SetupFakeDriver]
  389. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Right ()
  390. {
  391. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  392. view.Border.Thickness = new Thickness (1, 1, 0, 1);
  393. view.BeginInit ();
  394. view.EndInit ();
  395. view.SetRelativeLayout (Application.Screen.Size);
  396. Assert.Equal (new (0, 0, 1, 2), view.Frame);
  397. Assert.Equal (Rectangle.Empty, view.Viewport);
  398. view.Draw ();
  399. TestHelpers.AssertDriverContentsWithFrameAre (
  400. """
  401. """,
  402. _output
  403. );
  404. }
  405. [Fact]
  406. [SetupFakeDriver]
  407. public void Draw_Minimum_Full_Border_With_Empty_Viewport_Without_Top ()
  408. {
  409. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  410. view.Border.Thickness = new Thickness (1, 0, 1, 1);
  411. view.BeginInit ();
  412. view.EndInit ();
  413. view.SetRelativeLayout (Application.Screen.Size);
  414. Assert.Equal (new (0, 0, 2, 1), view.Frame);
  415. Assert.Equal (Rectangle.Empty, view.Viewport);
  416. view.Draw ();
  417. TestHelpers.AssertDriverContentsWithFrameAre ("││",
  418. _output
  419. );
  420. }
  421. [Fact]
  422. [AutoInitShutdown]
  423. public void Draw_Negative_Viewport_Horizontal_With_New_Lines ()
  424. {
  425. var subView = new View
  426. {
  427. Id = "subView",
  428. X = 1,
  429. Width = 1,
  430. Height = 7,
  431. Text = """
  432. s
  433. u
  434. b
  435. V
  436. i
  437. e
  438. w
  439. """
  440. };
  441. var view = new View
  442. {
  443. Id = "view", Width = 2, Height = 20, Text = """
  444. 0
  445. 1
  446. 2
  447. 3
  448. 4
  449. 5
  450. 6
  451. 7
  452. 8
  453. 9
  454. 0
  455. 1
  456. 2
  457. 3
  458. 4
  459. 5
  460. 6
  461. 7
  462. 8
  463. 9
  464. """
  465. };
  466. view.Add (subView);
  467. var content = new View { Id = "content", Width = 20, Height = 20 };
  468. content.Add (view);
  469. var container = new View
  470. {
  471. Id = "container",
  472. X = 1,
  473. Y = 1,
  474. Width = 5,
  475. Height = 5
  476. };
  477. container.Add (content);
  478. Toplevel top = new ();
  479. top.Add (container);
  480. Application.Driver.Clip = container.Frame;
  481. Application.Begin (top);
  482. TestHelpers.AssertDriverContentsWithFrameAre (
  483. """
  484. 0s
  485. 1u
  486. 2b
  487. 3V
  488. 4i
  489. """,
  490. _output
  491. );
  492. content.X = -1;
  493. Application.Refresh ();
  494. TestHelpers.AssertDriverContentsWithFrameAre (
  495. """
  496. s
  497. u
  498. b
  499. V
  500. i
  501. """,
  502. _output
  503. );
  504. content.X = -2;
  505. Application.Refresh ();
  506. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  507. content.X = 0;
  508. content.Y = -1;
  509. Application.Refresh ();
  510. TestHelpers.AssertDriverContentsWithFrameAre (
  511. """
  512. 1u
  513. 2b
  514. 3V
  515. 4i
  516. 5e
  517. """,
  518. _output
  519. );
  520. content.Y = -6;
  521. Application.Refresh ();
  522. TestHelpers.AssertDriverContentsWithFrameAre (
  523. """
  524. 6w
  525. 7
  526. 8
  527. 9
  528. 0
  529. """,
  530. _output
  531. );
  532. content.Y = -19;
  533. Application.Refresh ();
  534. TestHelpers.AssertDriverContentsWithFrameAre (
  535. """
  536. 9
  537. """,
  538. _output
  539. );
  540. content.Y = -20;
  541. Application.Refresh ();
  542. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  543. content.X = -2;
  544. content.Y = 0;
  545. Application.Refresh ();
  546. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  547. top.Dispose ();
  548. }
  549. [Fact]
  550. [AutoInitShutdown]
  551. public void Draw_Negative_Viewport_Horizontal_Without_New_Lines ()
  552. {
  553. // BUGBUG: This previously assumed the default height of a View was 1.
  554. var subView = new View
  555. {
  556. Id = "subView",
  557. Y = 1,
  558. Width = 7,
  559. Height = 1,
  560. Text = "subView"
  561. };
  562. var view = new View { Id = "view", Width = 20, Height = 2, Text = "01234567890123456789" };
  563. view.Add (subView);
  564. var content = new View { Id = "content", Width = 20, Height = 20 };
  565. content.Add (view);
  566. var container = new View
  567. {
  568. Id = "container",
  569. X = 1,
  570. Y = 1,
  571. Width = 5,
  572. Height = 5
  573. };
  574. container.Add (content);
  575. Toplevel top = new ();
  576. top.Add (container);
  577. // BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
  578. top.LayoutComplete += Top_LayoutComplete;
  579. Application.Begin (top);
  580. TestHelpers.AssertDriverContentsWithFrameAre (
  581. """
  582. 01234
  583. subVi
  584. """,
  585. _output
  586. );
  587. content.X = -1;
  588. Application.Refresh ();
  589. TestHelpers.AssertDriverContentsWithFrameAre (
  590. """
  591. 12345
  592. ubVie
  593. """,
  594. _output
  595. );
  596. content.Y = -1;
  597. Application.Refresh ();
  598. TestHelpers.AssertDriverContentsWithFrameAre (
  599. """
  600. ubVie
  601. """,
  602. _output
  603. );
  604. content.Y = -2;
  605. Application.Refresh ();
  606. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  607. content.X = -20;
  608. content.Y = 0;
  609. Application.Refresh ();
  610. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  611. top.Dispose ();
  612. return;
  613. void Top_LayoutComplete (object? sender, LayoutEventArgs e) { Application.Driver.Clip = container.Frame; }
  614. }
  615. [Fact]
  616. [AutoInitShutdown]
  617. public void Draw_Negative_Viewport_Vertical ()
  618. {
  619. var subView = new View
  620. {
  621. Id = "subView",
  622. X = 1,
  623. Width = 1,
  624. Height = 7,
  625. Text = "subView",
  626. TextDirection = TextDirection.TopBottom_LeftRight
  627. };
  628. var view = new View
  629. {
  630. Id = "view",
  631. Width = 2,
  632. Height = 20,
  633. Text = "01234567890123456789",
  634. TextDirection = TextDirection.TopBottom_LeftRight
  635. };
  636. view.Add (subView);
  637. var content = new View { Id = "content", Width = 20, Height = 20 };
  638. content.Add (view);
  639. var container = new View
  640. {
  641. Id = "container",
  642. X = 1,
  643. Y = 1,
  644. Width = 5,
  645. Height = 5
  646. };
  647. container.Add (content);
  648. Toplevel top = new ();
  649. top.Add (container);
  650. Application.Driver.Clip = container.Frame;
  651. Application.Begin (top);
  652. TestHelpers.AssertDriverContentsWithFrameAre (
  653. """
  654. 0s
  655. 1u
  656. 2b
  657. 3V
  658. 4i
  659. """,
  660. _output
  661. );
  662. content.X = -1;
  663. Application.Refresh ();
  664. TestHelpers.AssertDriverContentsWithFrameAre (
  665. """
  666. s
  667. u
  668. b
  669. V
  670. i
  671. """,
  672. _output
  673. );
  674. content.X = -2;
  675. Application.Refresh ();
  676. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  677. content.X = 0;
  678. content.Y = -1;
  679. Application.Refresh ();
  680. TestHelpers.AssertDriverContentsWithFrameAre (
  681. """
  682. 1u
  683. 2b
  684. 3V
  685. 4i
  686. 5e
  687. """,
  688. _output
  689. );
  690. content.Y = -6;
  691. Application.Refresh ();
  692. TestHelpers.AssertDriverContentsWithFrameAre (
  693. """
  694. 6w
  695. 7
  696. 8
  697. 9
  698. 0
  699. """,
  700. _output
  701. );
  702. content.Y = -19;
  703. Application.Refresh ();
  704. TestHelpers.AssertDriverContentsWithFrameAre (
  705. """
  706. 9
  707. """,
  708. _output
  709. );
  710. content.Y = -20;
  711. Application.Refresh ();
  712. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  713. content.X = -2;
  714. content.Y = 0;
  715. Application.Refresh ();
  716. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  717. top.Dispose ();
  718. }
  719. [Theory]
  720. [SetupFakeDriver]
  721. [InlineData ("𝔽𝕆𝕆𝔹𝔸R")]
  722. [InlineData ("a𐐀b")]
  723. public void DrawHotString_NonBmp (string expected)
  724. {
  725. var view = new View { Width = 10, Height = 1 };
  726. view.DrawHotString (expected, Attribute.Default, Attribute.Default);
  727. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  728. }
  729. // TODO: The tests below that use Label should use View instead.
  730. [Fact]
  731. [AutoInitShutdown]
  732. public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
  733. {
  734. var us = "\U0001d539";
  735. var r = (Rune)0x1d539;
  736. Assert.Equal ("𝔹", us);
  737. Assert.Equal ("𝔹", r.ToString ());
  738. Assert.Equal (us, r.ToString ());
  739. Assert.Equal (1, us.GetColumns ());
  740. Assert.Equal (1, r.GetColumns ());
  741. var win = new Window { Title = us };
  742. var view = new Label { Text = r.ToString () };
  743. var tf = new TextField { Text = us, Y = 1, Width = 3 };
  744. win.Add (view, tf);
  745. Toplevel top = new ();
  746. top.Add (win);
  747. Application.Begin (top);
  748. ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
  749. var expected = """
  750. ┌┤𝔹├─────┐
  751. │𝔹 │
  752. │𝔹 │
  753. └────────┘
  754. """;
  755. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  756. TestHelpers.AssertDriverContentsAre (expected, _output);
  757. top.Dispose ();
  758. // This test has nothing to do with color - removing as it is not relevant and fragile
  759. }
  760. [Fact]
  761. [SetupFakeDriver]
  762. public void SetClip_ClipVisibleContentOnly_VisibleContentIsClipped ()
  763. {
  764. // Screen is 25x25
  765. // View is 25x25
  766. // Viewport is (0, 0, 23, 23)
  767. // ContentSize is (10, 10)
  768. // ViewportToScreen is (1, 1, 23, 23)
  769. // Visible content is (1, 1, 10, 10)
  770. // Expected clip is (1, 1, 10, 10) - same as visible content
  771. Rectangle expectedClip = new (1, 1, 10, 10);
  772. // Arrange
  773. var view = new View ()
  774. {
  775. Width = Dim.Fill (),
  776. Height = Dim.Fill (),
  777. ViewportSettings = ViewportSettings.ClipContentOnly
  778. };
  779. view.SetContentSize (new Size (10, 10));
  780. view.Border.Thickness = new Thickness (1);
  781. view.BeginInit ();
  782. view.EndInit ();
  783. Assert.Equal (view.Frame, Application.Driver.Clip);
  784. // Act
  785. view.SetClip ();
  786. // Assert
  787. Assert.Equal (expectedClip, Application.Driver.Clip);
  788. view.Dispose ();
  789. }
  790. [Fact]
  791. [SetupFakeDriver]
  792. public void SetClip_Default_ClipsToViewport ()
  793. {
  794. // Screen is 25x25
  795. // View is 25x25
  796. // Viewport is (0, 0, 23, 23)
  797. // ContentSize is (10, 10)
  798. // ViewportToScreen is (1, 1, 23, 23)
  799. // Visible content is (1, 1, 10, 10)
  800. // Expected clip is (1, 1, 23, 23) - same as Viewport
  801. Rectangle expectedClip = new (1, 1, 23, 23);
  802. // Arrange
  803. var view = new View ()
  804. {
  805. Width = Dim.Fill (),
  806. Height = Dim.Fill (),
  807. };
  808. view.SetContentSize (new Size (10, 10));
  809. view.Border.Thickness = new Thickness (1);
  810. view.BeginInit ();
  811. view.EndInit ();
  812. Assert.Equal (view.Frame, Application.Driver.Clip);
  813. view.Viewport = view.Viewport with { X = 1, Y = 1 };
  814. // Act
  815. view.SetClip ();
  816. // Assert
  817. Assert.Equal (expectedClip, Application.Driver.Clip);
  818. view.Dispose ();
  819. }
  820. [Fact]
  821. [TestRespondersDisposed]
  822. public void Draw_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
  823. {
  824. Application.Init (new FakeDriver ());
  825. Toplevel top = new ();
  826. var view = new View { X = -2, Text = "view" };
  827. top.Add (view);
  828. Application.Iteration += (s, a) =>
  829. {
  830. Assert.Equal (-2, view.X);
  831. Application.RequestStop ();
  832. };
  833. try
  834. {
  835. Application.Run (top);
  836. }
  837. catch (IndexOutOfRangeException ex)
  838. {
  839. // After the fix this exception will not be caught.
  840. Assert.IsType<IndexOutOfRangeException> (ex);
  841. }
  842. top.Dispose ();
  843. // Shutdown must be called to safely clean up Application if Init has been called
  844. Application.Shutdown ();
  845. }
  846. }