DrawTests.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. using System.Text;
  2. using Xunit;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewsTests;
  5. public class DrawTests {
  6. readonly ITestOutputHelper _output;
  7. public DrawTests (ITestOutputHelper output) => _output = output;
  8. // TODO: Refactor this test to not depend on TextView etc... Make it as primitive as possible
  9. [Fact]
  10. [AutoInitShutdown]
  11. public void Clipping_AddRune_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
  12. {
  13. var tv = new TextView () {
  14. Width = Dim.Fill (),
  15. Height = Dim.Fill (),
  16. Text = @"これは広いルーンラインです。
  17. これは広いルーンラインです。
  18. これは広いルーンラインです。
  19. これは広いルーンラインです。
  20. これは広いルーンラインです。
  21. これは広いルーンラインです。
  22. これは広いルーンラインです。
  23. これは広いルーンラインです。"
  24. };
  25. var win = new Window () { Width = Dim.Fill (), Height = Dim.Fill () };
  26. win.Add (tv);
  27. Application.Top.Add (win);
  28. // Don't use Label. It sets AutoSize = true which is not what we're testing here.
  29. var lbl = new View ("ワイドルーン。");
  30. // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
  31. var dg = new Window () { X = 2, Y = 2, Width = 14, Height = 3 };
  32. dg.Add (lbl);
  33. Application.Begin (Application.Top);
  34. Application.Begin (dg);
  35. ((FakeDriver)Application.Driver).SetBufferSize (30, 10);
  36. string expected = @$"
  37. ┌────────────────────────────┐
  38. │これは広いルーンラインです。│
  39. │�┌────────────┐�ラインです。│
  40. │�│ワイドルーン│�ラインです。│
  41. │�└────────────┘�ラインです。│
  42. │これは広いルーンラインです。│
  43. │これは広いルーンラインです。│
  44. │これは広いルーンラインです。│
  45. │これは広いルーンラインです。│
  46. └────────────────────────────┘";
  47. var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  48. Assert.Equal (new Rect (0, 0, 30, 10), pos);
  49. }
  50. // TODO: The tests below that use Label should use View instead.
  51. [Fact]
  52. [AutoInitShutdown]
  53. public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
  54. {
  55. string us = "\U0001d539";
  56. var r = (Rune)0x1d539;
  57. Assert.Equal ("𝔹", us);
  58. Assert.Equal ("𝔹", r.ToString ());
  59. Assert.Equal (us, r.ToString ());
  60. Assert.Equal (1, us.GetColumns ());
  61. Assert.Equal (1, r.GetColumns ());
  62. var win = new Window () { Title = us };
  63. var label = new Label (r.ToString ());
  64. var tf = new TextField (us) { Y = 1, Width = 3 };
  65. win.Add (label, tf);
  66. var top = Application.Top;
  67. top.Add (win);
  68. Application.Begin (top);
  69. ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
  70. string expected = @"
  71. ┌┤𝔹├─────┐
  72. │𝔹 │
  73. │𝔹 │
  74. └────────┘";
  75. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  76. TestHelpers.AssertDriverContentsAre (expected, _output);
  77. var expectedColors = new Attribute [] {
  78. // 0
  79. Colors.ColorSchemes ["Base"].Normal,
  80. // 1
  81. Colors.ColorSchemes ["Base"].Focus,
  82. // 2
  83. Colors.ColorSchemes ["Base"].HotNormal
  84. };
  85. TestHelpers.AssertDriverAttributesAre (@"
  86. 0010000000
  87. 0000000000
  88. 0111000000
  89. 0000000000", Application.Driver, expectedColors);
  90. }
  91. [Fact]
  92. [AutoInitShutdown]
  93. public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two ()
  94. {
  95. string us = "\U0000f900";
  96. var r = (Rune)0xf900;
  97. Assert.Equal ("豈", us);
  98. Assert.Equal ("豈", r.ToString ());
  99. Assert.Equal (us, r.ToString ());
  100. Assert.Equal (2, us.GetColumns ());
  101. Assert.Equal (2, r.GetColumns ());
  102. var win = new Window () { Title = us };
  103. var label = new Label (r.ToString ());
  104. var tf = new TextField (us) { Y = 1, Width = 3 };
  105. win.Add (label, tf);
  106. var top = Application.Top;
  107. top.Add (win);
  108. Application.Begin (top);
  109. ((FakeDriver)Application.Driver).SetBufferSize (10, 4);
  110. string expected = @"
  111. ┌┤豈├────┐
  112. │豈 │
  113. │豈 │
  114. └────────┘";
  115. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  116. TestHelpers.AssertDriverContentsAre (expected, _output);
  117. var expectedColors = new Attribute [] {
  118. // 0
  119. Colors.ColorSchemes ["Base"].Normal,
  120. // 1
  121. Colors.ColorSchemes ["Base"].Focus,
  122. // 2
  123. Colors.ColorSchemes ["Base"].HotNormal
  124. };
  125. TestHelpers.AssertDriverAttributesAre (@"
  126. 0011000000
  127. 0000000000
  128. 0111000000
  129. 0000000000", Application.Driver, expectedColors);
  130. }
  131. [Fact]
  132. [AutoInitShutdown]
  133. public void Colors_On_TextAlignment_Right_And_Bottom ()
  134. {
  135. var labelRight = new Label ("Test") {
  136. Width = 6,
  137. Height = 1,
  138. TextAlignment = TextAlignment.Right,
  139. ColorScheme = Colors.ColorSchemes ["Base"]
  140. };
  141. var labelBottom = new Label ("Test", TextDirection.TopBottom_LeftRight) {
  142. Y = 1,
  143. Width = 1,
  144. Height = 6,
  145. VerticalTextAlignment = VerticalTextAlignment.Bottom,
  146. ColorScheme = Colors.ColorSchemes ["Base"]
  147. };
  148. var top = Application.Top;
  149. top.Add (labelRight, labelBottom);
  150. Application.Begin (top);
  151. ((FakeDriver)Application.Driver).SetBufferSize (7, 7);
  152. TestHelpers.AssertDriverContentsWithFrameAre (@"
  153. Test
  154. T
  155. e
  156. s
  157. t ", _output);
  158. TestHelpers.AssertDriverAttributesAre (@"
  159. 000000
  160. 0
  161. 0
  162. 0
  163. 0
  164. 0
  165. 0", Application.Driver, new Attribute [] { Colors.ColorSchemes ["Base"].Normal });
  166. }
  167. [Fact]
  168. [AutoInitShutdown]
  169. public void Draw_Negative_Bounds_Horizontal_Without_New_Lines ()
  170. {
  171. // BUGBUG: This previously assumed the default height of a View was 1.
  172. var subView = new View () { Id = "subView", Y = 1, Width = 7, Height = 1, Text = "subView" };
  173. var view = new View () { Id = "view", Width = 20, Height = 2, Text = "01234567890123456789" };
  174. view.Add (subView);
  175. var content = new View () { Id = "content", Width = 20, Height = 20 };
  176. content.Add (view);
  177. var container = new View () { Id = "container", X = 1, Y = 1, Width = 5, Height = 5 };
  178. container.Add (content);
  179. var top = Application.Top;
  180. top.Add (container);
  181. // BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
  182. void Top_LayoutComplete (object sender, LayoutEventArgs e) => Application.Driver.Clip = container.Frame;
  183. top.LayoutComplete += Top_LayoutComplete;
  184. Application.Begin (top);
  185. TestHelpers.AssertDriverContentsWithFrameAre (@"
  186. 01234
  187. subVi", _output);
  188. content.X = -1;
  189. Application.Refresh ();
  190. TestHelpers.AssertDriverContentsWithFrameAre (@"
  191. 12345
  192. ubVie", _output);
  193. content.Y = -1;
  194. Application.Refresh ();
  195. TestHelpers.AssertDriverContentsWithFrameAre (@"
  196. ubVie", _output);
  197. content.Y = -2;
  198. Application.Refresh ();
  199. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  200. content.X = -20;
  201. content.Y = 0;
  202. Application.Refresh ();
  203. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  204. }
  205. [Fact]
  206. [AutoInitShutdown]
  207. public void Draw_Negative_Bounds_Horizontal_With_New_Lines ()
  208. {
  209. var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "s\nu\nb\nV\ni\ne\nw" };
  210. var view = new View () { Id = "view", Width = 2, Height = 20, Text = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9" };
  211. view.Add (subView);
  212. var content = new View () { Id = "content", Width = 20, Height = 20 };
  213. content.Add (view);
  214. var container = new View () { Id = "container", X = 1, Y = 1, Width = 5, Height = 5 };
  215. container.Add (content);
  216. var top = Application.Top;
  217. top.Add (container);
  218. Application.Driver.Clip = container.Frame;
  219. Application.Begin (top);
  220. TestHelpers.AssertDriverContentsWithFrameAre (@"
  221. 0s
  222. 1u
  223. 2b
  224. 3V
  225. 4i", _output);
  226. content.X = -1;
  227. Application.Refresh ();
  228. TestHelpers.AssertDriverContentsWithFrameAre (@"
  229. s
  230. u
  231. b
  232. V
  233. i", _output);
  234. content.X = -2;
  235. Application.Refresh ();
  236. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  237. content.X = 0;
  238. content.Y = -1;
  239. Application.Refresh ();
  240. TestHelpers.AssertDriverContentsWithFrameAre (@"
  241. 1u
  242. 2b
  243. 3V
  244. 4i
  245. 5e", _output);
  246. content.Y = -6;
  247. Application.Refresh ();
  248. TestHelpers.AssertDriverContentsWithFrameAre (@"
  249. 6w
  250. 7
  251. 8
  252. 9
  253. 0 ", _output);
  254. content.Y = -19;
  255. Application.Refresh ();
  256. TestHelpers.AssertDriverContentsWithFrameAre (@"
  257. 9", _output);
  258. content.Y = -20;
  259. Application.Refresh ();
  260. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  261. content.X = -2;
  262. content.Y = 0;
  263. Application.Refresh ();
  264. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  265. }
  266. [Fact]
  267. [AutoInitShutdown]
  268. public void Draw_Negative_Bounds_Vertical ()
  269. {
  270. var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "subView", TextDirection = TextDirection.TopBottom_LeftRight };
  271. var view = new View () { Id = "view", Width = 2, Height = 20, Text = "01234567890123456789", TextDirection = TextDirection.TopBottom_LeftRight };
  272. view.Add (subView);
  273. var content = new View () { Id = "content", Width = 20, Height = 20 };
  274. content.Add (view);
  275. var container = new View () { Id = "container", X = 1, Y = 1, Width = 5, Height = 5 };
  276. container.Add (content);
  277. var top = Application.Top;
  278. top.Add (container);
  279. Application.Driver.Clip = container.Frame;
  280. Application.Begin (top);
  281. TestHelpers.AssertDriverContentsWithFrameAre (@"
  282. 0s
  283. 1u
  284. 2b
  285. 3V
  286. 4i", _output);
  287. content.X = -1;
  288. Application.Refresh ();
  289. TestHelpers.AssertDriverContentsWithFrameAre (@"
  290. s
  291. u
  292. b
  293. V
  294. i", _output);
  295. content.X = -2;
  296. Application.Refresh ();
  297. TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
  298. content.X = 0;
  299. content.Y = -1;
  300. Application.Refresh ();
  301. TestHelpers.AssertDriverContentsWithFrameAre (@"
  302. 1u
  303. 2b
  304. 3V
  305. 4i
  306. 5e", _output);
  307. content.Y = -6;
  308. Application.Refresh ();
  309. TestHelpers.AssertDriverContentsWithFrameAre (@"
  310. 6w
  311. 7
  312. 8
  313. 9
  314. 0 ", _output);
  315. content.Y = -19;
  316. Application.Refresh ();
  317. TestHelpers.AssertDriverContentsWithFrameAre (@"
  318. 9", _output);
  319. content.Y = -20;
  320. Application.Refresh ();
  321. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  322. content.X = -2;
  323. content.Y = 0;
  324. Application.Refresh ();
  325. TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
  326. }
  327. [Theory, SetupFakeDriver]
  328. [InlineData ("𝔽𝕆𝕆𝔹𝔸R")]
  329. [InlineData ("a𐐀b")]
  330. void DrawHotString_NonBmp (string expected)
  331. {
  332. var view = new View () { Width = 10, Height = 1 };
  333. view.DrawHotString (expected, Attribute.Default, Attribute.Default);
  334. TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
  335. }
  336. [Fact, AutoInitShutdown]
  337. public void Draw_Minimum_Full_Border_With_Empty_Bounds ()
  338. {
  339. var label = new Label () { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
  340. Application.Top.Add (label);
  341. Application.Begin (Application.Top);
  342. Assert.Equal ("(0,0,2,2)", label.Frame.ToString ());
  343. Assert.Equal ("(0,0,0,0)", label.Bounds.ToString ());
  344. TestHelpers.AssertDriverContentsWithFrameAre (@"
  345. ┌┐
  346. └┘", _output);
  347. }
  348. [Fact, AutoInitShutdown]
  349. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Top ()
  350. {
  351. var label = new Label () { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  352. label.Border.Thickness = new Thickness (1, 0, 1, 1);
  353. Application.Top.Add (label);
  354. Application.Begin (Application.Top);
  355. Assert.Equal ("(0,0,2,1)", label.Frame.ToString ());
  356. Assert.Equal ("(0,0,0,0)", label.Bounds.ToString ());
  357. // BUGBUG: Top thickness is 0 and top shouldn't draw,
  358. // but my changes weren't merged and TabViewTests passed
  359. // without them and thus I give up
  360. // The output before was ││ but I think it's also correct └┘
  361. TestHelpers.AssertDriverContentsWithFrameAre (@"
  362. ┌┐", _output);
  363. }
  364. [Fact, AutoInitShutdown]
  365. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Bottom ()
  366. {
  367. var label = new Label () { Width = 2, Height = 1, BorderStyle = LineStyle.Single };
  368. label.Border.Thickness = new Thickness (1, 1, 1, 0);
  369. Application.Top.Add (label);
  370. Application.Begin (Application.Top);
  371. Assert.Equal ("(0,0,2,1)", label.Frame.ToString ());
  372. Assert.Equal ("(0,0,0,0)", label.Bounds.ToString ());
  373. // BUGBUG: Bottom thickness is 0 and bottom shouldn't draw,
  374. // but my changes weren't merged and TabViewTests passed
  375. // without them and thus I give up
  376. // The output before was ── but I think it's also correct ┌┐
  377. TestHelpers.AssertDriverContentsWithFrameAre (@"
  378. ", _output);
  379. }
  380. [Fact, AutoInitShutdown]
  381. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Left ()
  382. {
  383. var label = new Label () { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  384. label.Border.Thickness = new Thickness (0, 1, 1, 1);
  385. Application.Top.Add (label);
  386. Application.Begin (Application.Top);
  387. Assert.Equal ("(0,0,1,2)", label.Frame.ToString ());
  388. Assert.Equal ("(0,0,0,0)", label.Bounds.ToString ());
  389. TestHelpers.AssertDriverContentsWithFrameAre (@"
  390. │", _output);
  391. }
  392. [Fact, AutoInitShutdown]
  393. public void Draw_Minimum_Full_Border_With_Empty_Bounds_Without_Right ()
  394. {
  395. var label = new Label () { Width = 1, Height = 2, BorderStyle = LineStyle.Single };
  396. label.Border.Thickness = new Thickness (1, 1, 0, 1);
  397. Application.Top.Add (label);
  398. Application.Begin (Application.Top);
  399. Assert.Equal ("(0,0,1,2)", label.Frame.ToString ());
  400. Assert.Equal ("(0,0,0,0)", label.Bounds.ToString ());
  401. TestHelpers.AssertDriverContentsWithFrameAre (@"
  402. │", _output);
  403. }
  404. [Fact, AutoInitShutdown]
  405. public void Test_Label_Full_Border ()
  406. {
  407. var label = new Label () { Text = "Test", Width = 6, Height = 3, BorderStyle = LineStyle.Single };
  408. Application.Top.Add (label);
  409. Application.Begin (Application.Top);
  410. Assert.Equal (new Rect (0, 0, 6, 3), label.Frame);
  411. Assert.Equal (new Rect (0, 0, 4, 1), label.Bounds);
  412. TestHelpers.AssertDriverContentsWithFrameAre (@"
  413. ┌────┐
  414. │Test│
  415. └────┘", _output);
  416. }
  417. [Fact, AutoInitShutdown]
  418. public void Test_Label_Without_Top_Border ()
  419. {
  420. var label = new Label () { Text = "Test", Width = 6, Height = 3, BorderStyle = LineStyle.Single };
  421. label.Border.Thickness = new Thickness (1, 0, 1, 1);
  422. Application.Top.Add (label);
  423. Application.Begin (Application.Top);
  424. Assert.Equal (new Rect (0, 0, 6, 3), label.Frame);
  425. Assert.Equal (new Rect (0, 0, 4, 2), label.Bounds);
  426. Application.Begin (Application.Top);
  427. TestHelpers.AssertDriverContentsWithFrameAre (@"
  428. │Test│
  429. │ │
  430. └────┘", _output);
  431. }
  432. [Fact, AutoInitShutdown]
  433. public void Test_Label_With_Top_Margin_Without_Top_Border ()
  434. {
  435. var label = new Label () { Text = "Test", Width = 6, Height = 3, BorderStyle = LineStyle.Single };
  436. label.Margin.Thickness = new Thickness (0, 1, 0, 0);
  437. label.Border.Thickness = new Thickness (1, 0, 1, 1);
  438. Application.Top.Add (label);
  439. Application.Begin (Application.Top);
  440. Assert.Equal (new Rect (0, 0, 6, 3), label.Frame);
  441. Assert.Equal (new Rect (0, 0, 4, 1), label.Bounds);
  442. Application.Begin (Application.Top);
  443. TestHelpers.AssertDriverContentsWithFrameAre (@"
  444. │Test│
  445. └────┘", _output);
  446. }
  447. }