LineCanvasTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Terminal.Gui.Graphs;
  5. using Xunit;
  6. using Xunit.Abstractions;
  7. namespace Terminal.Gui.CoreTests {
  8. public class LineCanvasTests {
  9. readonly ITestOutputHelper output;
  10. public LineCanvasTests (ITestOutputHelper output)
  11. {
  12. this.output = output;
  13. }
  14. [InlineData (BorderStyle.Single)]
  15. [InlineData (BorderStyle.Rounded)]
  16. [Theory, AutoInitShutdown]
  17. public void TestLineCanvas_Horizontal (BorderStyle style)
  18. {
  19. var v = GetCanvas (out var canvas);
  20. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, style);
  21. v.Redraw (v.Bounds);
  22. string looksLike =
  23. @"
  24. ──";
  25. TestHelpers.AssertDriverContentsAre (looksLike, output);
  26. }
  27. [Fact, AutoInitShutdown]
  28. public void TestLineCanvas_Horizontal_Double ()
  29. {
  30. var v = GetCanvas (out var canvas);
  31. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Double);
  32. v.Redraw (v.Bounds);
  33. string looksLike =
  34. @"
  35. ══";
  36. TestHelpers.AssertDriverContentsAre (looksLike, output);
  37. }
  38. [InlineData (BorderStyle.Single)]
  39. [InlineData (BorderStyle.Rounded)]
  40. [Theory, AutoInitShutdown]
  41. public void TestLineCanvas_Vertical (BorderStyle style)
  42. {
  43. var v = GetCanvas (out var canvas);
  44. canvas.AddLine (new Point (0, 0), 1, Orientation.Vertical, style);
  45. v.Redraw (v.Bounds);
  46. string looksLike =
  47. @"
  48. │";
  49. TestHelpers.AssertDriverContentsAre (looksLike, output);
  50. }
  51. [Fact, AutoInitShutdown]
  52. public void TestLineCanvas_Vertical_Double ()
  53. {
  54. var v = GetCanvas (out var canvas);
  55. canvas.AddLine (new Point (0, 0), 1, Orientation.Vertical, BorderStyle.Double);
  56. v.Redraw (v.Bounds);
  57. string looksLike =
  58. @"
  59. ║";
  60. TestHelpers.AssertDriverContentsAre (looksLike, output);
  61. }
  62. /// <summary>
  63. /// This test demonstrates that corners are only drawn when lines overlap.
  64. /// Not when they terminate adjacent to one another.
  65. /// </summary>
  66. [Fact, AutoInitShutdown]
  67. public void TestLineCanvas_Corner_NoOverlap ()
  68. {
  69. var v = GetCanvas (out var canvas);
  70. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Single);
  71. canvas.AddLine (new Point (0, 1), 1, Orientation.Vertical, BorderStyle.Single);
  72. v.Redraw (v.Bounds);
  73. string looksLike =
  74. @"
  75. ──
  76. │";
  77. TestHelpers.AssertDriverContentsAre (looksLike, output);
  78. }
  79. /// <summary>
  80. /// This test demonstrates how to correctly trigger a corner. By
  81. /// overlapping the lines in the same cell
  82. /// </summary>
  83. [Fact, AutoInitShutdown]
  84. public void TestLineCanvas_Corner_Correct ()
  85. {
  86. var v = GetCanvas (out var canvas);
  87. canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Single);
  88. canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, BorderStyle.Single);
  89. v.Redraw (v.Bounds);
  90. string looksLike =
  91. @"
  92. ┌─
  93. │";
  94. TestHelpers.AssertDriverContentsAre (looksLike, output);
  95. }
  96. [Fact, AutoInitShutdown]
  97. public void TestLineCanvas_Window ()
  98. {
  99. var v = GetCanvas (out var canvas);
  100. // outer box
  101. canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Single);
  102. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Single);
  103. canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Single);
  104. canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Single);
  105. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Single);
  106. canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Single);
  107. v.Redraw (v.Bounds);
  108. string looksLike =
  109. @"
  110. ┌────┬───┐
  111. │ │ │
  112. ├────┼───┤
  113. │ │ │
  114. └────┴───┘";
  115. TestHelpers.AssertDriverContentsAre (looksLike, output);
  116. }
  117. /// <summary>
  118. /// Demonstrates when <see cref="BorderStyle.Rounded"/> corners are used. Notice how
  119. /// not all lines declare rounded. If there are 1+ lines intersecting and a corner is
  120. /// to be used then if any of them are rounded a rounded corner is used.
  121. /// </summary>
  122. [Fact, AutoInitShutdown]
  123. public void TestLineCanvas_Window_Rounded ()
  124. {
  125. var v = GetCanvas (out var canvas);
  126. // outer box
  127. canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Rounded);
  128. // BorderStyle.Single is ignored because corner overlaps with the above line which is Rounded
  129. // this results in a rounded corner being used.
  130. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Single);
  131. canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Rounded);
  132. canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Single);
  133. // These lines say rounded but they will result in the T sections which are never rounded.
  134. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Rounded);
  135. canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Rounded);
  136. v.Redraw (v.Bounds);
  137. string looksLike =
  138. @"
  139. ╭────┬───╮
  140. │ │ │
  141. ├────┼───┤
  142. │ │ │
  143. ╰────┴───╯";
  144. TestHelpers.AssertDriverContentsAre (looksLike, output);
  145. }
  146. [Fact, AutoInitShutdown]
  147. public void TestLineCanvas_Window_Double ()
  148. {
  149. var v = GetCanvas (out var canvas);
  150. // outer box
  151. canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Double);
  152. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Double);
  153. canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Double);
  154. canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Double);
  155. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Double);
  156. canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Double);
  157. v.Redraw (v.Bounds);
  158. string looksLike =
  159. @"
  160. ╔════╦═══╗
  161. ║ ║ ║
  162. ╠════╬═══╣
  163. ║ ║ ║
  164. ╚════╩═══╝";
  165. TestHelpers.AssertDriverContentsAre (looksLike, output);
  166. }
  167. [Theory, AutoInitShutdown]
  168. [InlineData (BorderStyle.Single)]
  169. [InlineData (BorderStyle.Rounded)]
  170. public void TestLineCanvas_Window_DoubleTop_SingleSides (BorderStyle thinStyle)
  171. {
  172. var v = GetCanvas (out var canvas);
  173. // outer box
  174. canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Double);
  175. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, thinStyle);
  176. canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Double);
  177. canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, thinStyle);
  178. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, thinStyle);
  179. canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Double);
  180. v.Redraw (v.Bounds);
  181. string looksLike =
  182. @"
  183. ╒════╤═══╕
  184. │ │ │
  185. ╞════╪═══╡
  186. │ │ │
  187. ╘════╧═══╛
  188. ";
  189. TestHelpers.AssertDriverContentsAre (looksLike, output);
  190. }
  191. [Theory, AutoInitShutdown]
  192. [InlineData (BorderStyle.Single)]
  193. [InlineData (BorderStyle.Rounded)]
  194. public void TestLineCanvas_Window_SingleTop_DoubleSides (BorderStyle thinStyle)
  195. {
  196. var v = GetCanvas (out var canvas);
  197. // outer box
  198. canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, thinStyle);
  199. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Double);
  200. canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, thinStyle);
  201. canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Double);
  202. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Double);
  203. canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, thinStyle);
  204. v.Redraw (v.Bounds);
  205. string looksLike =
  206. @"
  207. ╓────╥───╖
  208. ║ ║ ║
  209. ╟────╫───╢
  210. ║ ║ ║
  211. ╙────╨───╜
  212. ";
  213. TestHelpers.AssertDriverContentsAre (looksLike, output);
  214. }
  215. [Fact, AutoInitShutdown]
  216. public void TestLineCanvas_LeaveMargin_Top1_Left1 ()
  217. {
  218. // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1)
  219. var v = GetCanvas (out var canvas, 1, 1);
  220. // outer box
  221. canvas.AddLine (new Point (0, 0), 8, Orientation.Horizontal, BorderStyle.Single);
  222. canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, BorderStyle.Single);
  223. canvas.AddLine (new Point (8, 3), -8, Orientation.Horizontal, BorderStyle.Single);
  224. canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, BorderStyle.Single);
  225. canvas.AddLine (new Point (5, 0), 3, Orientation.Vertical, BorderStyle.Single);
  226. canvas.AddLine (new Point (0, 2), 8, Orientation.Horizontal, BorderStyle.Single);
  227. v.Redraw (v.Bounds);
  228. string looksLike =
  229. @"
  230. ┌────┬──┐
  231. │ │ │
  232. ├────┼──┤
  233. └────┴──┘
  234. ";
  235. TestHelpers.AssertDriverContentsAre (looksLike, output);
  236. }
  237. [Fact, AutoInitShutdown]
  238. public void TestLineCanvas_ClipArea_Intersections ()
  239. {
  240. // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1)
  241. var v = GetCanvas (out var lc);
  242. v.Width = 10;
  243. v.Height = 1;
  244. v.Bounds = new Rect (0, 0, 10, 1);
  245. // ╔╡ Title ╞═════╗
  246. // Add a short horiz line for ╔╡
  247. lc.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Double);
  248. //LHS line down
  249. lc.AddLine (new Point (0, 0), 5, Orientation.Vertical, BorderStyle.Double);
  250. //Vertical line before Title, results in a ╡
  251. lc.AddLine (new Point (1, 0), 0, Orientation.Vertical, BorderStyle.Single);
  252. //Vertical line after Title, results in a ╞
  253. lc.AddLine (new Point (6, 0), 0, Orientation.Vertical, BorderStyle.Single);
  254. // remainder of title
  255. lc.AddLine (new Point (6, 0), 3, Orientation.Horizontal, BorderStyle.Double);
  256. //RHS line down
  257. lc.AddLine (new Point (9, 0), 5, Orientation.Vertical, BorderStyle.Double);
  258. v.Redraw (v.Bounds);
  259. string looksLike =
  260. @"
  261. ╔╡ ╞══╗
  262. ";
  263. TestHelpers.AssertDriverContentsAre (looksLike, output);
  264. }
  265. [InlineData(0,0,0, Orientation.Horizontal,BorderStyle.Double,"═")]
  266. [InlineData(0,0,0, Orientation.Vertical,BorderStyle.Double,"║")]
  267. [InlineData(0,0,0, Orientation.Horizontal,BorderStyle.Single,"─")]
  268. [InlineData(0,0,0, Orientation.Vertical,BorderStyle.Single,"│")]
  269. [AutoInitShutdown, Theory]
  270. public void TestLineCanvas_1LineTests(
  271. int x1, int y1,int l1, Orientation o1, BorderStyle s1,
  272. string expected
  273. )
  274. {
  275. var v = GetCanvas (out var lc);
  276. v.Width = 10;
  277. v.Height = 10;
  278. v.Bounds = new Rect (0, 0, 10, 10);
  279. lc.AddLine (new Point (x1, y1), l1, o1, s1);
  280. v.Redraw (v.Bounds);
  281. TestHelpers.AssertDriverContentsAre (expected, output);
  282. }
  283. [Theory, AutoInitShutdown]
  284. [InlineData(
  285. 0,0,1,Orientation.Horizontal,BorderStyle.Double,
  286. 1,0,0, Orientation.Vertical,BorderStyle.Single, "═╡"
  287. )]
  288. [InlineData(
  289. 0,0,0, Orientation.Vertical,BorderStyle.Single,
  290. 0,0,1,Orientation.Horizontal,BorderStyle.Double,
  291. "╞═"
  292. )]
  293. [InlineData(
  294. 0,0,1, Orientation.Vertical,BorderStyle.Single,
  295. 0,0,0,Orientation.Horizontal,BorderStyle.Double,
  296. @"
  297. │"
  298. )]
  299. [InlineData(
  300. 0,0,1, Orientation.Vertical,BorderStyle.Single,
  301. 0,1,0,Orientation.Horizontal,BorderStyle.Double,
  302. @"
  303. "
  304. )]
  305. [InlineData(
  306. 0,0,0, Orientation.Vertical,BorderStyle.Single,
  307. 0,0,0,Orientation.Horizontal,BorderStyle.Single,
  308. @"┼
  309. "
  310. )]
  311. [InlineData(
  312. 0,0,0, Orientation.Vertical,BorderStyle.Double,
  313. 0,0,0,Orientation.Horizontal,BorderStyle.Double,
  314. @"╬
  315. "
  316. )]
  317. public void TestLineCanvas_2LineTests(
  318. int x1, int y1,int l1, Orientation o1, BorderStyle s1,
  319. int x2, int y2, int l2, Orientation o2, BorderStyle s2,
  320. string expected
  321. )
  322. {
  323. var v = GetCanvas (out var lc);
  324. v.Width = 10;
  325. v.Height = 10;
  326. v.Bounds = new Rect (0, 0, 10, 10);
  327. lc.AddLine (new Point (x1, y1), l1, o1, s1);
  328. lc.AddLine (new Point (x2, y2), l2, o2, s2);
  329. v.Redraw (v.Bounds);
  330. TestHelpers.AssertDriverContentsAre (expected, output);
  331. }
  332. /// <summary>
  333. /// Creates a new <see cref="View"/> into which a <see cref="LineCanvas"/> is rendered
  334. /// at <see cref="View.DrawContentComplete"/> time.
  335. /// </summary>
  336. /// <param name="canvas">The <see cref="LineCanvas"/> you can draw into.</param>
  337. /// <param name="offsetX">How far to offset drawing in X</param>
  338. /// <param name="offsetY">How far to offset drawing in Y</param>
  339. /// <returns></returns>
  340. private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0)
  341. {
  342. var v = new View {
  343. Width = 10,
  344. Height = 5,
  345. Bounds = new Rect (0, 0, 10, 5)
  346. };
  347. var canvasCopy = canvas = new LineCanvas ();
  348. v.DrawContentComplete += (s, e) => {
  349. foreach(var p in canvasCopy.GenerateImage(v.Bounds))
  350. {
  351. v.AddRune(
  352. offsetX + p.Key.X,
  353. offsetY + p.Key.Y,
  354. p.Value);
  355. }
  356. };
  357. return v;
  358. }
  359. }
  360. }