DrawTests.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. #nullable enable
  2. using System.Text;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewsTests;
  5. [Trait("Category","Output")]
  6. public class DrawTests
  7. {
  8. private readonly ITestOutputHelper _output;
  9. public DrawTests (ITestOutputHelper output) { _output = output; }
  10. [Fact]
  11. [AutoInitShutdown]
  12. [Trait("Category","Unicode")]
  13. public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two ()
  14. {
  15. const string us = "\U0000f900";
  16. var r = (Rune)0xf900;
  17. Assert.Equal ("豈", us);
  18. Assert.Equal ("豈", r.ToString ());
  19. Assert.Equal (us, r.ToString ());
  20. Assert.Equal (2, us.GetColumns ());
  21. Assert.Equal (2, r.GetColumns ());
  22. var win = new Window { Title = us };
  23. var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill () };
  24. var tf = new TextField { Text = us, Y = 1, Width = 3 };
  25. win.Add (view, tf);
  26. Toplevel top = Application.Top;
  27. top.Add (win);
  28. Application.Begin (top);
  29. ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
  30. const string expectedOutput = """
  31. ┌┤豈├────┐
  32. │豈 │
  33. │豈 │
  34. └────────┘
  35. """;
  36. TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  37. TestHelpers.AssertDriverContentsAre (expectedOutput, _output);
  38. Attribute [] expectedColors =
  39. {
  40. // 0
  41. Colors.ColorSchemes ["Base"].Normal,
  42. // 1
  43. Colors.ColorSchemes ["Base"].Focus,
  44. // 2
  45. Colors.ColorSchemes ["Base"].HotNormal
  46. };
  47. TestHelpers.AssertDriverAttributesAre (
  48. """
  49. 0011000000
  50. 0000000000
  51. 0111000000
  52. 0000000000
  53. """,
  54. Application.Driver,
  55. expectedColors
  56. );
  57. }
  58. // TODO: Refactor this test to not depend on TextView etc... Make it as primitive as possible
  59. [Fact]
  60. [AutoInitShutdown]
  61. [Trait("Category","Unicode")]
  62. public void Clipping_AddRune_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
  63. {
  64. var tv = new TextView
  65. {
  66. Width = Dim.Fill (),
  67. Height = Dim.Fill (),
  68. Text = """
  69. これは広いルーンラインです。
  70. これは広いルーンラインです。
  71. これは広いルーンラインです。
  72. これは広いルーンラインです。
  73. これは広いルーンラインです。
  74. これは広いルーンラインです。
  75. これは広いルーンラインです。
  76. これは広いルーンラインです。
  77. """
  78. };
  79. var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
  80. win.Add (tv);
  81. Application.Top.Add (win);
  82. // Don't use Label. It sets AutoSize = true which is not what we're testing here.
  83. var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
  84. // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
  85. var dg = new Window { X = 2, Y = 2, Width = 14, Height = 3 };
  86. dg.Add (view);
  87. Application.Begin (Application.Top);
  88. Application.Begin (dg);
  89. ((FakeDriver)Application.Driver).SetBufferSize (30, 10);
  90. const string expectedOutput = """
  91. ┌────────────────────────────┐
  92. │これは広いルーンラインです。│
  93. │�┌────────────┐�ラインです。│
  94. │�│ワイドルーン│�ラインです。│
  95. │�└────────────┘�ラインです。│
  96. │これは広いルーンラインです。│
  97. │これは広いルーンラインです。│
  98. │これは広いルーンラインです。│
  99. │これは広いルーンラインです。│
  100. └────────────────────────────┘
  101. """;
  102. Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
  103. Assert.Equal (new Rectangle (0, 0, 30, 10), pos);
  104. }
  105. [Fact]
  106. [AutoInitShutdown]
  107. [Trait("Category","Output")]
  108. public void Colors_On_TextAlignment_Right_And_Bottom ()
  109. {
  110. var viewRight = new View
  111. {
  112. Text = "Test",
  113. Width = 6,
  114. Height = 1,
  115. TextAlignment = TextAlignment.Right,
  116. ColorScheme = Colors.ColorSchemes ["Base"]
  117. };
  118. var viewBottom = new View
  119. {
  120. Text = "Test",
  121. TextDirection = TextDirection.TopBottom_LeftRight,
  122. Y = 1,
  123. Width = 1,
  124. Height = 6,
  125. VerticalTextAlignment = VerticalTextAlignment.Bottom,
  126. ColorScheme = Colors.ColorSchemes ["Base"]
  127. };
  128. Toplevel top = Application.Top;
  129. top.Add (viewRight, viewBottom);
  130. Application.Begin (top);
  131. ((FakeDriver)Application.Driver).SetBufferSize (7, 7);
  132. TestHelpers.AssertDriverContentsWithFrameAre (
  133. """
  134. Test
  135. T
  136. e
  137. s
  138. t
  139. """,
  140. _output
  141. );
  142. TestHelpers.AssertDriverAttributesAre (
  143. """
  144. 000000
  145. 0
  146. 0
  147. 0
  148. 0
  149. 0
  150. 0
  151. """,
  152. Application.Driver,
  153. Colors.ColorSchemes ["Base"].Normal
  154. );
  155. }
  156. [Fact]
  157. [SetupFakeDriver]
  158. public void Draw_Minimum_Full_Border_With_Empty_Bounds ()
  159. {
  160. var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
  161. view.BeginInit ();
  162. view.EndInit ();
  163. view.SetRelativeLayout (Application.Driver.Bounds);
  164. Assert.Equal (new (0,0,2,2), view.Frame);
  165. Assert.Equal (Rectangle.Empty, view.Bounds);
  166. view.Draw ();
  167. TestHelpers.AssertDriverContentsWithFrameAre (
  168. """
  169. ┌┐
  170. └┘
  171. """,
  172. _output
  173. );
  174. }
  175. [Fact]
  176. [SetupFakeDriver]
  177. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Bottom ()
  178. {
  179. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  180. view.Border.Thickness = new Thickness (1, 1, 1, 0);
  181. view.BeginInit ();
  182. view.EndInit ();
  183. view.SetRelativeLayout (Application.Driver.Bounds);
  184. Assert.Equal (new (0,0,2,1), view.Frame);
  185. Assert.Equal (Rectangle.Empty, view.Bounds);
  186. view.Draw ();
  187. TestHelpers.AssertDriverContentsWithFrameAre (string.Empty, _output);
  188. }
  189. [Fact]
  190. [SetupFakeDriver]
  191. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Left ()
  192. {
  193. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  194. view.Border.Thickness = new Thickness (0, 1, 1, 1);
  195. view.BeginInit ();
  196. view.EndInit ();
  197. view.SetRelativeLayout (Application.Driver.Bounds);
  198. Assert.Equal (new (0,0,1,2), view.Frame);
  199. Assert.Equal (Rectangle.Empty, view.Bounds);
  200. view.Draw ();
  201. TestHelpers.AssertDriverContentsWithFrameAre (
  202. """
  203. """,
  204. _output
  205. );
  206. }
  207. [Fact]
  208. [SetupFakeDriver]
  209. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Right ()
  210. {
  211. var view = new View { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  212. view.Border.Thickness = new Thickness (1, 1, 0, 1);
  213. view.BeginInit ();
  214. view.EndInit ();
  215. view.SetRelativeLayout (Application.Driver.Bounds);
  216. Assert.Equal (new (0,0,1,2), view.Frame);
  217. Assert.Equal (Rectangle.Empty, view.Bounds);
  218. view.Draw ();
  219. TestHelpers.AssertDriverContentsWithFrameAre (
  220. """
  221. """,
  222. _output
  223. );
  224. }
  225. [Fact]
  226. [SetupFakeDriver]
  227. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Top ()
  228. {
  229. var view = new View { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  230. view.Border.Thickness = new Thickness (1, 0, 1, 1);
  231. view.BeginInit ();
  232. view.EndInit ();
  233. view.SetRelativeLayout (Application.Driver.Bounds);
  234. Assert.Equal (new (0,0,2,1), view.Frame);
  235. Assert.Equal (Rectangle.Empty, view.Bounds);
  236. view.Draw ();
  237. // BUGBUG: Wha? Is this right? Shouldn't it be "└┘"???
  238. TestHelpers.AssertDriverContentsWithFrameAre (
  239. """
  240. ┌┐
  241. """,
  242. _output
  243. );
  244. }
  245. [Fact]
  246. [AutoInitShutdown]
  247. public void Draw_Negative_Bounds_Horizontal_With_New_Lines ()
  248. {
  249. var subView = new View
  250. {
  251. Id = "subView",
  252. X = 1,
  253. Width = 1,
  254. Height = 7,
  255. Text = """
  256. s
  257. u
  258. b
  259. V
  260. i
  261. e
  262. w
  263. """
  264. };
  265. var view = new View
  266. {
  267. Id = "view", Width = 2, Height = 20, Text = """
  268. 0
  269. 1
  270. 2
  271. 3
  272. 4
  273. 5
  274. 6
  275. 7
  276. 8
  277. 9
  278. 0
  279. 1
  280. 2
  281. 3
  282. 4
  283. 5
  284. 6
  285. 7
  286. 8
  287. 9
  288. """
  289. };
  290. view.Add (subView);
  291. var content = new View { Id = "content", Width = 20, Height = 20 };
  292. content.Add (view);
  293. var container = new View
  294. {
  295. Id = "container",
  296. X = 1,
  297. Y = 1,
  298. Width = 5,
  299. Height = 5
  300. };
  301. container.Add (content);
  302. Toplevel top = Application.Top;
  303. top.Add (container);
  304. Application.Driver.Clip = container.Frame;
  305. Application.Begin (top);
  306. TestHelpers.AssertDriverContentsWithFrameAre (
  307. """
  308. 0s
  309. 1u
  310. 2b
  311. 3V
  312. 4i
  313. """,
  314. _output
  315. );
  316. content.X = -1;
  317. Application.Refresh ();
  318. TestHelpers.AssertDriverContentsWithFrameAre (
  319. """
  320. s
  321. u
  322. b
  323. V
  324. i
  325. """,
  326. _output
  327. );
  328. content.X = -2;
  329. Application.Refresh ();
  330. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  331. content.X = 0;
  332. content.Y = -1;
  333. Application.Refresh ();
  334. TestHelpers.AssertDriverContentsWithFrameAre (
  335. """
  336. 1u
  337. 2b
  338. 3V
  339. 4i
  340. 5e
  341. """,
  342. _output
  343. );
  344. content.Y = -6;
  345. Application.Refresh ();
  346. TestHelpers.AssertDriverContentsWithFrameAre (
  347. """
  348. 6w
  349. 7
  350. 8
  351. 9
  352. 0
  353. """,
  354. _output
  355. );
  356. content.Y = -19;
  357. Application.Refresh ();
  358. TestHelpers.AssertDriverContentsWithFrameAre (
  359. """
  360. 9
  361. """,
  362. _output
  363. );
  364. content.Y = -20;
  365. Application.Refresh ();
  366. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  367. content.X = -2;
  368. content.Y = 0;
  369. Application.Refresh ();
  370. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  371. }
  372. [Fact]
  373. [AutoInitShutdown]
  374. public void Draw_Negative_Bounds_Horizontal_Without_New_Lines ()
  375. {
  376. // BUGBUG: This previously assumed the default height of a View was 1.
  377. var subView = new View
  378. {
  379. Id = "subView",
  380. Y = 1,
  381. Width = 7,
  382. Height = 1,
  383. Text = "subView"
  384. };
  385. var view = new View { Id = "view", Width = 20, Height = 2, Text = "01234567890123456789" };
  386. view.Add (subView);
  387. var content = new View { Id = "content", Width = 20, Height = 20 };
  388. content.Add (view);
  389. var container = new View
  390. {
  391. Id = "container",
  392. X = 1,
  393. Y = 1,
  394. Width = 5,
  395. Height = 5
  396. };
  397. container.Add (content);
  398. Toplevel top = Application.Top;
  399. top.Add (container);
  400. // BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
  401. void Top_LayoutComplete (object sender, LayoutEventArgs e) { Application.Driver.Clip = container.Frame; }
  402. top.LayoutComplete += Top_LayoutComplete;
  403. Application.Begin (top);
  404. TestHelpers.AssertDriverContentsWithFrameAre (
  405. """
  406. 01234
  407. subVi
  408. """,
  409. _output
  410. );
  411. content.X = -1;
  412. Application.Refresh ();
  413. TestHelpers.AssertDriverContentsWithFrameAre (
  414. """
  415. 12345
  416. ubVie
  417. """,
  418. _output
  419. );
  420. content.Y = -1;
  421. Application.Refresh ();
  422. TestHelpers.AssertDriverContentsWithFrameAre (
  423. """
  424. ubVie
  425. """,
  426. _output
  427. );
  428. content.Y = -2;
  429. Application.Refresh ();
  430. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  431. content.X = -20;
  432. content.Y = 0;
  433. Application.Refresh ();
  434. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  435. }
  436. [Fact]
  437. [AutoInitShutdown]
  438. public void Draw_Negative_Bounds_Vertical ()
  439. {
  440. var subView = new View
  441. {
  442. Id = "subView",
  443. X = 1,
  444. Width = 1,
  445. Height = 7,
  446. Text = "subView",
  447. TextDirection = TextDirection.TopBottom_LeftRight
  448. };
  449. var view = new View
  450. {
  451. Id = "view",
  452. Width = 2,
  453. Height = 20,
  454. Text = "01234567890123456789",
  455. TextDirection = TextDirection.TopBottom_LeftRight
  456. };
  457. view.Add (subView);
  458. var content = new View { Id = "content", Width = 20, Height = 20 };
  459. content.Add (view);
  460. var container = new View
  461. {
  462. Id = "container",
  463. X = 1,
  464. Y = 1,
  465. Width = 5,
  466. Height = 5
  467. };
  468. container.Add (content);
  469. Toplevel top = Application.Top;
  470. top.Add (container);
  471. Application.Driver.Clip = container.Frame;
  472. Application.Begin (top);
  473. TestHelpers.AssertDriverContentsWithFrameAre (
  474. """
  475. 0s
  476. 1u
  477. 2b
  478. 3V
  479. 4i
  480. """,
  481. _output
  482. );
  483. content.X = -1;
  484. Application.Refresh ();
  485. TestHelpers.AssertDriverContentsWithFrameAre (
  486. """
  487. s
  488. u
  489. b
  490. V
  491. i
  492. """,
  493. _output
  494. );
  495. content.X = -2;
  496. Application.Refresh ();
  497. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  498. content.X = 0;
  499. content.Y = -1;
  500. Application.Refresh ();
  501. TestHelpers.AssertDriverContentsWithFrameAre (
  502. """
  503. 1u
  504. 2b
  505. 3V
  506. 4i
  507. 5e
  508. """,
  509. _output
  510. );
  511. content.Y = -6;
  512. Application.Refresh ();
  513. TestHelpers.AssertDriverContentsWithFrameAre (
  514. """
  515. 6w
  516. 7
  517. 8
  518. 9
  519. 0
  520. """,
  521. _output
  522. );
  523. content.Y = -19;
  524. Application.Refresh ();
  525. TestHelpers.AssertDriverContentsWithFrameAre (
  526. """
  527. 9
  528. """,
  529. _output
  530. );
  531. content.Y = -20;
  532. Application.Refresh ();
  533. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  534. content.X = -2;
  535. content.Y = 0;
  536. Application.Refresh ();
  537. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  538. }
  539. [Theory]
  540. [SetupFakeDriver]
  541. [InlineData ("𝔽𝕆𝕆𝔹𝔸R")]
  542. [InlineData ("a𐐀b")]
  543. public void DrawHotString_NonBmp (string expected)
  544. {
  545. var view = new View { Width = 10, Height = 1 };
  546. view.DrawHotString (expected, Attribute.Default, Attribute.Default);
  547. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  548. }
  549. // TODO: The tests below that use Label should use View instead.
  550. [Fact]
  551. [AutoInitShutdown]
  552. public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
  553. {
  554. var us = "\U0001d539";
  555. var r = (Rune)0x1d539;
  556. Assert.Equal ("𝔹", us);
  557. Assert.Equal ("𝔹", r.ToString ());
  558. Assert.Equal (us, r.ToString ());
  559. Assert.Equal (1, us.GetColumns ());
  560. Assert.Equal (1, r.GetColumns ());
  561. var win = new Window { Title = us };
  562. var view = new Label { Text = r.ToString () };
  563. var tf = new TextField { Text = us, Y = 1, Width = 3 };
  564. win.Add (view, tf);
  565. Toplevel top = Application.Top;
  566. top.Add (win);
  567. Application.Begin (top);
  568. ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
  569. var expected = """
  570. ┌┤𝔹├─────┐
  571. │𝔹 │
  572. │𝔹 │
  573. └────────┘
  574. """;
  575. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  576. TestHelpers.AssertDriverContentsAre (expected, _output);
  577. Attribute [] expectedColors =
  578. {
  579. // 0
  580. Colors.ColorSchemes ["Base"].Normal,
  581. // 1
  582. Colors.ColorSchemes ["Base"].Focus,
  583. // 2
  584. Colors.ColorSchemes ["Base"].HotNormal
  585. };
  586. TestHelpers.AssertDriverAttributesAre (
  587. """
  588. 0010000000
  589. 0000000000
  590. 0111000000
  591. 0000000000
  592. """,
  593. Application.Driver,
  594. expectedColors
  595. );
  596. }
  597. }